常用的最短路算法有三种(Disjkstra,Floyd,Ballman-Floyd)
一、Disjkstra算法
Dijkstra算法要求图上的权非负数。同样使用于无向图;
- #include<stdio.h> //HDU 2544
- #define maxsum 0x7fffffff //重点
- int map[101][101],dist[101],s[101];
- void Dijkstra(int x,int n) //x为起点,n为顶点个数
- {
- int mindis,u;
- for(int i=1;i<=n;i++)
- {
- dist[i]=map[x][i];
- s[i]=0; //s集合为空
- }
- s[x]=1; //s进入集合中
- for(int i=1;i<=n;i++)
- {
- mindis=maxsum;
- u=-1;
- for(int j=1;j<=n;j++)
- if(!s[j]&&dist[j]<mindis)//贪心算法,每次找出x通向?的最短路
- {
- u=j;
- mindis=dist[j];
- }
- s[u]=1; //表明该路顶点进入集合s
- for(int j=1;j<=n;j++)
- if(s[j]==0) //未进入s集合的点
- if(dist[u]+map[u][j]<dist[j]&&map[u][j]<maxsum) 对比直接到达的路和间接到达的路 权map[u][j]必须实际存在
- dist[j]=dist[u]+map[u][j]; //
- }
- }
- int main()
- {
- int n,m,a,b,c;
- while(scanf("%d%d",&n,&m)!=EOF)
- {
- if(n==0&&m==0) break;
- while(~scanf("%d%d",&m,&n))
- {
- for(i=0;i<m;i++)
- {
- for(j=0;j<m;j++)
- if(i==j)map[i][j]=0; //impotant
- else map[i][j]=maxsum;
- }
- for(i=0;i<n;i++)
- {
- scanf("%d%d%d",&a,&b,&c);
- if(c<map[a][b]) //可能有重边,就是说两点之间的path不唯一 //impotant
- map[a][b]=map[b][a]=c;
- }
- scanf("%d%d",&s,&e);s为起始点,e为终止点
- Dijkstra(s,n); //需遍历所有顶点
- printf("%d\n",dist[e]);
- }
- return 0;
- }
二、Floyd算法
可以处理负权边,但无法处理负环,效率低,空间开销大,对于密集点图较为实用
本质是动态规划,要求图上没有负环,否则会导致死循环,可用于无向图,此时一个无向边相当于两个有向边
- #include<stdio.h> //HDU 1874
- #define MAX 99999999 //切忌max不能定义为0xfffffff,下面有两个map相加
- int main()
- {
- int i,j,k,n,m,x,y,a,b,c,map[201][201];
- while(~scanf("%d%d",&m,&n))
- {
- for(i=0;i<m;i++)
- {
- for(j=0;j<m;j++)
- if(i==j)map[i][j]=0;
- else map[i][j]=MAX;
- }
- for(i=0;i<n;i++)
- {
- scanf("%d%d%d",&a,&b,&c);
- if(c<map[a][b]) //可能有重边,就是说两点之间的path不唯一
- map[a][b]=map[b][a]=c;
- }
- scanf("%d%d",&x,&y);
- for(k=0;k<m;k++) //k为“中转站”
- {
- for(i=0;i<m;i++)
- for(j=0;j<m;j++)
- if(map[i][j]>map[i][k]+map[k][j])//i到j的最短距离
- map[i][j]=map[i][k]+map[k][j];
- }
- if(map[x][y]<MAX) printf("%d\n",map[x][y]);
- else printf("-1\n");
- }
- return 0;
- }
三、Bellman-Floyd算法
可以是负权值,可以判断是否为负环(非常好用)
- include <iostream>
- using namespace std;
- const int maxnum = 100;
- const int maxint = 99999;
- // 边,
- typedef struct Edge{
- int u, v; // 起点,重点
- int weight; // 边的权值
- }Edge;
- Edge edge[maxnum]; // 保存边的值
- int dist[maxnum]; // 结点到源点最小距离
- int nodenum, edgenum, source; // 结点数,边数,源点
- // 初始化图
- void init()
- {
- // 输入结点数,边数,源点
- cin >> nodenum >> edgenum >> source;
- for(int i=1; i<=nodenum; ++i)
- dist[i] = maxint;
- dist[source] = 0;
- for(int i=1; i<=edgenum; ++i)
- {
- cin >> edge[i].u >> edge[i].v >> edge[i].weight;
- if(edge[i].u == source) //注意这里设置初始情况
- dist[edge[i].v] = edge[i].weight;
- }
- }
- // 松弛计算
- void relax(int u, int v, int weight)
- {
- if(dist[v] > dist[u] + weight)
- dist[v] = dist[u] + weight;
- }
- bool Bellman_Ford()
- {
- bool finish = true; // 加个全部完成松弛的判断,优化了50多MS。
- for(int i=1; i<=nodenum-1; ++i)
- {bool finish = true;
- for(int j=1; j<=edgenum; ++j)
- {
- relax(edge[j].u, edge[j].v, edge[j].weight);
- finish=false;
- }
- if(finish)
- break;
- }
- bool flag = 1;
- // 判断是否有负环路
- for(int i=1; i<=edgenum; ++i)
- if(dist[edge[i].v] > dist[edge[i].u] + edge[i].weight)
- {
- flag = 0;
- break;
- }
- return flag;
- }
- int main()
- {
- //freopen("input3.txt", "r", stdin);
- init();
- if(Bellman_Ford())
- for(int i = 1 ;i <= nodenum; i++)
- cout << dist[i] << endl;
- return 0;
- }