四种常用最短路径算法模板
来源:互联网 发布:远大精英咨询 知乎 编辑:程序博客网 时间:2024/05/17 12:54
转自:http://www.cnblogs.com/genyuan/archive/2013/05/01/3053904.html
最短路径算法中,有四种算法是最常见的,分别是Dijkstra算法,Floyd算法,Bellman-Ford算法和SPFA算法。
Dijkstra算法,求单源最短路径最稳定的一个算法,算法复杂度为O(n2),但可以通过队列优化。下面列出的模板是最原始的Dijkstra算法。以需要求的源为中心,向四周扩散,第一次求出的是与源直接相连接的点的距离。求出这些距离中的最短距离,然后通过这个点将与它相连接的点的最短距离更新,然后再求出现在的最短距离,如此这样下去,直到所有的点都已经被遍历过为止。已经求出最短距离的点不在参与更新。具体模板如下(以POJ3268为例):
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <cstdlib> 6 #include <algorithm> 7 #include <queue> 8 #include <vector> 9 #include <map>10 using namespace std;11 #define INF 0x7ffffff12 #define eps 1e-813 #define sgn(a) (a>eps)-(a<-eps)14 #define LL long long15 #define out(v) cerr << #v << ": " << (v) << endl16 #define SZ(v) ((int)(v).size())17 const int maxint = -1u>>1;20 int n,m,x;21 const int maxn = 1111;22 int dist[maxn];23 int dist2[maxn];24 int d[maxn][maxn];25 bool flag[maxn];26 27 void Dijkstra(int x)28 {29 memset(flag,false,sizeof(flag));30 for(int i=1;i<=n;++i)31 {32 dist[i] = d[x][i];33 }34 flag[x] = true;35 dist[x] = 0;36 37 for(int i=2;i<=n;++i)38 {39 //寻找没有标记而且dist值最小的点40 int u = 1;41 int mindis = maxint;42 for(int j=1;j<=n;++j)43 {44 if(!flag[j] && dist[j] < mindis)45 {46 mindis = dist[j];47 u = j;48 }49 }50 flag[u] = true;51 for(int j=1;j<=n;++j)52 {53 if(!flag[j] && d[u][j] < maxint)54 {55 dist[j] = min(dist[j],dist[u] + d[u][j]);56 }57 }58 }59 }60 61 62 int main()63 {64 while(scanf("%d%d%d",&n,&m,&x) != EOF)65 {66 int a,b,len;67 for(int i=1;i<=n;++i)68 {69 for(int j=1;j<=n;++j)70 {71 d[i][j] = maxint;72 }73 }74 for(int i=1;i<=m;++i)75 {76 scanf("%d%d%d",&a,&b,&len);77 d[a][b] = len;78 }79 Dijkstra(x);80 for(int i=1;i<=n;++i) dist2[i] = dist[i];81 for(int i=1;i<=n;++i)82 {83 for(int j=i+1;j<=n;++j)84 {85 swap(d[i][j],d[j][i]);86 }87 }88 Dijkstra(x);89 int ans = 0;90 for(int i=1;i<=n;++i)91 {92 ans = max(ans,dist[i] + dist2[i]);93 }94 printf("%d\n",ans);95 }96 return 0;97 }
Floyd算法其实是Floyd-Warshall算法的简称。分以下两步进行。
1 /* 2 * Author: xiagenyuan 3 * Created Time: 2013/5/1 21:03:44 4 * File Name: D:\ACMICPC\20130501\POJ2240.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <cmath>10 #include <string>11 #include <algorithm>12 #include <queue>13 #include <vector>14 #include <map>15 using namespace std;16 #define eps 1e-817 #define sgn(a) (a>eps)-(a<-eps)18 #define LL long long19 const int maxint = -1u>>1;20 const int maxn = 33;21 int n,m;22 map<string,int> mp;//用来为名字是字符串的点对应数字23 double ra[maxn][maxn]; //存取两点间的的路径24 25 void Floyd()//对临接表进行Floyd处理26 {27 for(int k=1;k<=n;++k)28 {29 for(int i=1;i<=n;++i)30 {31 for(int j=1;j<=n;++j)32 {33 if(ra[i][j] < ra[i][k]*ra[k][j])34 {35 ra[i][j] = ra[i][k]*ra[k][j];36 }37 }38 }39 }40 }41 42 int main()43 {44 int cas = 1;45 while(scanf("%d",&n) != EOF && n)46 {47 mp.clear();48 string name;49 for(int i=1;i<=n;++i)50 {51 cin>>name;52 mp[name]=i;53 }54 scanf("%d",&m);55 string name1,name2;56 double rate;57 memset(ra,1,sizeof(ra));58 for(int i=1;i<=m;++i)59 {60 cin>>name1>>rate>>name2;61 ra[mp[name1]][mp[name2]]= rate;62 }63 Floyd();64 bool flag = false;65 for(int i=1;i<=n;++i)66 {67 if(ra[i][i] > 1) 68 {69 flag = true;70 break;71 }72 }73 if(flag) printf("Case %d: Yes\n",cas);74 else printf("Case %d: No\n",cas);75 cas++;76 }77 return 0;78 }
Bellman-Ford算法
1、以下操作循环执行至多n-1次,n为顶点数:
2、对于每一条边e(u, v),如果Distant[u] + w(u, v) < Distant[v],则另Distant[v] = Distant[u]+w(u, v)。w(u, v)为边e(u,v)的权值;
若上述操作没有对Distant进行更新,说明最短路径已经查找完毕,或者部分点不可达,跳出循环。否则执行下次循环;
3、为了检测图中是否存在负环路,即权值之和小于0的环路。对于每一条边e(u, v),如果存在Distant[u] + w(u, v) < Distant[v]的边,则图中存在负环路,即是说改图无法求出单源最短路径。否则数组Distant[n]中记录的就是源点s到各顶点的最短路径长度。
具体模板如下所示:
1 /* 2 * Author: xiagenyuan 3 * Created Time: 2013/5/1 21:39:36 4 * File Name: C:\Users\Genyuan\Desktop\图论系列模板\Bellman-Ford.cpp 5 */ 6 //模板未进行验证 7 #include <iostream> 8 #include <cstdio> 9 #include <cstring>10 #include <cmath>11 #include <string>12 #include <algorithm>13 #include <queue>14 #include <vector>15 #include <map>16 using namespace std;17 #define eps 1e-818 #define sgn(a) (a>eps)-(a<-eps)19 #define LL long long20 const int maxint = 9999999;21 const int maxnum = 100;22 struct edge23 {24 int u,v;//每条边的起点和终点25 int weight;//边的权值26 };27 edge e[maxnum];//保存所有边的值28 int dist[maxnum]; //保存节点到源点的最短距离29 int n,m,x; //节点数量,边的数量,源点30 31 //读入数据,初始化图32 void init()33 {34 while(scanf("%d%d%d",&n,&m,&x) != EOF)35 {36 for(int i=1;i<=n;++i) dist[i] = maxint;37 dist[x] = 0;38 for(int i=1;i<m;++i)39 {40 scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].weight);41 if(e[i].u == x) dist[e[i].v] = e[i].weight;42 }43 }44 }45 //松弛计算46 void relax(int u,int v,int weight)47 {48 dist[v] = min(dist[v],dist[u]+weight);49 }50 51 bool BellmanFord()52 {53 for(int i=1;i<n-1;++i)54 {55 for(int j=1;j<=m;++j)56 {57 relax(e[j].u,e[j].v,e[j].weight);58 }59 }60 bool flag = true;61 for(int i=1;i<m;++i)62 {63 if(dist[e[i].v] > dist[e[i].u]+e[i].weight)64 {65 flag = false;66 break;67 }68 }69 return flag;70 }71 72 int main()73 {74 init();75 if(BellmanFord())76 {77 for(int i=1;i<=m;++i) cout<<dist[i]<<" ";78 cout<<endl;79 }80 else cout<<"No"<<endl;81 return 0;82 }
SPFA算法其实就是Bellman-Ford算法,只是它用队列进行了优化。用队列进行优化有三种形式:
1、简单地用队列进行存储。
2、SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾。
3、LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i
出对进行松弛操作。
以下模板是针对第一种情况(POJ3268为例):
1 /* 2 * Author: xiagenyuan 3 * Created Time: 2013/5/1 22:26:23 4 * File Name: D:\ACMICPC\20130501\POJ3268SPFA.cpp 5 */ 6 #include <iostream> 7 #include <cstdio> 8 #include <cstring> 9 #include <cmath>10 #include <string>11 #include <algorithm>12 #include <queue>13 #include <vector>14 #include <map>15 using namespace std;16 #define eps 1e-817 #define sgn(a) (a>eps)-(a<-eps)18 #define LL long long19 const int maxint = 99999999;20 const int maxn = 1000 + 111;21 int n,m,x;22 int d[maxn][maxn];23 int dist[maxn];24 int dist2[maxn];25 bool visited[maxn];26 int que[2*maxn];27 28 void spfa()29 {30 int pri = 0,end = 1;31 memset(visited,false,sizeof(visited));32 visited[x] = true;33 for(int i=1;i<=n;++i) dist[i] = maxint;34 dist[x] = 0;35 que[0] = x;36 while(pri < end)37 {38 int index = que[pri];39 for(int i=1;i<=n;++i)40 {41 if(dist[index] + d[index][i] < dist[i])42 {43 dist[i] = dist[index] + d[index][i];44 if(!visited[i])45 {46 que[end++] = i;47 visited[i] = true;48 }49 }50 }51 visited[index] = false;52 pri++;53 } 54 }55 56 int main()57 {58 while(scanf("%d%d%d",&n,&m,&x) != EOF)59 {60 int a,b,len;61 for(int i=1;i<=n;++i)62 {63 for(int j=1;j<=n;++j)64 {65 d[i][j] = maxint;66 }67 }68 for(int i=1;i<=m;++i)69 {70 scanf("%d%d%d",&a,&b,&len);71 d[a][b] = len;72 }73 spfa();74 for(int i=1;i<=n;++i) dist2[i] = dist[i];75 for(int i=1;i<=n;++i)76 {77 for(int j=i+1;j<=n;++j)78 {79 swap(d[i][j],d[j][i]);80 }81 }82 spfa();83 int ans = 0;84 for(int i=1;i<=n;++i)85 {86 ans = max(ans,dist[i] + dist2[i]);87 }88 printf("%d\n",ans);89 }90 return 0;91 }
- 四种常用最短路径算法模板
- 四种常用最短路径算法模板
- 最短路径问题(算法模板)
- 最短路径Dijkstra算法模板
- 最短路径Floyd算法模板
- 最短路径bellman-ford算法模板
- 最短路径spfa算法模板
- dijkstra 最短路径算法模板
- 模板_Dijkstra最短路径算法
- 最短路径算法 模板_Dijkstra_Bellman.ford_Floyd_spfa
- 最短路径【迪杰斯特拉算法】【模板】
- 最短路径常用算法总结
- 最短路径模板
- 最短路径模板
- 最短路径算法模板:Dijkstra/Floyd/Bellman-Ford模板
- 最短路径算法
- 最短路径算法
- 最短路径算法
- Redis 事务
- 提高光耦传输速度的方法
- Freemarker 使用
- The Picture of Dorian Gray——13
- PAI注解 生成数据库是出现Could not load an Entity(......) 上图说明
- 四种常用最短路径算法模板
- 获取当前路径及写入excel
- FAR非暴力破解
- Java_对数据外螺旋方式排列
- Ubuntu 安装mate desktop environment.
- Hadoop操作HDFS命令
- 关于MFC中GetLastError函数返回值的含义(仅供参考)
- C++ hash_map
- 读取配置文件 某节点值