图论之单源最短路径问题

单源最短路径问题#

问题描述#

对一幅图G,我们对每一条边赋权w(e),成为一个赋权图。H是G的一个子图,则W(H) = sigma(w(e)),也就是对每条边的权求和。寻找从一个点a到另一个b的一个子图,使得权和最小,即为最短路问题。

Dijkstra(迪杰斯特拉算法算法):#

  • 把结点集分割为二子集S,T.开始时S={a},T=V-S.
  • 每结点t∈T,求出D(t,a)之后再定出x∈T使得D(x)= min{D(t,a)t∈T}.
  • 置S为S∪{x}置T为T-{x}.若T=O则停止,否则转(2)作下一次循环.
    用白话讲,迪杰特斯拉算法就是每次确定一个最短距离点,并用这个点去更新与之相连的其他边

算法流程#

1.先标记起点,然后从起点出发,得出到各个点的最小距离。
2.再每次找出还没有讨论过的离起点最近的那个点,从这个点出发,将前面得到的起点到各个点的最短路径和以这个点为中介点,再到各个点的距离大小作比较,取最小值。
时间复杂度o(n2)。

代码#

Copy
dij(){ for(int I=1;i<=n;i++){ int min=INF; int u=0; for(int v=1;v<=n;v++){ if(vis[v]==false&&dis[v]<min){//在没有访问过的点中选取最小的 min=dis[v]; u=v; } } if(u==0) break; vis[u]=true; for(int v=1;v<=n;v++) { if(dis[u]+w[u][v]<dis[v]){ dis[v]=dis[u]+w[u][v];//更新 pre[v]=u;//记录前驱 } }

Floyd算法#

插点法
dis[I][j]为i、j两点的距离。w[i][j]为i、j权值
若u、v有边,dis[u][v]=w[u][v]
否则dis[u][v]=0x3f3f3f3f(极大值)

代码#

Copy
for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j]; }

Ford 算法#

使用动态规划的想法,通过中介点。每次更新所有的边,从而确定一个点的最短距离。
其时间复杂度是 O(NNN),N是顶点数。

算法流程#

-起始时,认为起点是白点(dis[1]=0),每一次都枚举所有的边,必然会有一些边,连接着白点和蓝点。
-用所有的白点去修改所有的蓝点,每次循环也必然会有至少一个蓝点变成白点。

代码#

S为起点dis[v]表示从S到v的最短路径。u[i]和v[i]链接u(起点)v(终点)的边i的长度。

Copy
for(int i=0;i<n;i++) dis[i]=INF; dis[0]=0; for(int i=1;i<=n-1;i++){ for(int j=1;j<=m;j++){ int x=u[j];//得到j起点 int y=v[j];//得到j终点 if(dis[x]<INF) dis[y]=min(dis[y],dis[x]+dis[x]+w[j]); } }

SPFA 算法#

实质是 Ford 算法加了判断负环的队列实现版本。
其利用队列以进行 Ford 算法的过程,初始时将起点加入队列,每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若相邻的点修改成功,则将其入队,直到队列为空时算法结束。
SPFA 时间复杂度可达:O(k*E),其中,E 是边数,k 是常数,平均值是 2。

posted @   小帆敲代码  阅读(73)  评论(0编辑  收藏  举报
编辑推荐:
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
· 后端思维之高并发处理方案
· 理解Rust引用及其生命周期标识(下)
阅读排行:
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 当职场成战场:降职、阴谋与一场硬碰硬的抗争
· ShadowSql之.net sql拼写神器
· Excel百万数据如何快速导入?
· 无需WebView,Vue也能开发跨平台桌面应用
点击右上角即可分享
微信分享提示
CONTENTS