常用的最短路算法有三种(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;
}