Bellman-Ford算法 单源最短路径(o(nm))

来源:互联网 发布:mac艺术字体打包下载 编辑:程序博客网 时间:2024/05/18 00:58

解决的问题依旧是找出A城市到B城市的最短路径

Bellman-Ford算法,找出各个顶点间的最短路径,路径权值可以是负数,但是不能存在负权回路(在这一回路中存在负权路径)。
而Dijkstra算法,是找出某个顶点到其它顶点的最短路径。当然Dijkstra也可以找出各个顶点间的最短路径,只要做n次Dijkstra就行了。

思路:
对每对顶点i、j,不断缩小i到j的最短路径的权。在i、j中加入顶点k,判断从i到k和k到j路径的和是否小于i到j的路径长度,如果是将k加入,并调整i到j的路径长度。

缩小的条件: a[i][j]>a[i][k]+a[k][j]; (a:每对顶点的路径长度)

下面两组测试数组,前一组没构成负权回路,后一组是负权回路,无法得出正确结果

第一组:

5
1 2 6
2 3 5
3 2 -2
5 3 -3
4 3 7
2 4 -4
5 4 9
1 5 7
4 1 2
2 5 8
0 0 0

第二组:

3
1 2 2
2 3 3
3 1 -8
0 0 0

 


#include<stdio.h>
#define MAX 10000
 
/*路径长度矩阵*/
int a[100][100];
/*路径后继矩阵*/
int path[100][100];
/*路径权值矩阵*/
int c[100][100];
 
void Floyd(int n)
{
int i,j,k;
/*初始化a,path*/
for(i=1;i<=n;++i)
{
for(j=1;j<=n;++j)
{
if(c[i][j]!=MAX)
{
path[i][j]=j;
}
else
{
path[i][j]=-1;
}
a[i][j]=c[i][j];
}
}
/*尝试将顶点k扩充到已求得的从i到j的最短路径p上*/
for(k=1;k<=n;++k)
{
for(i=1;i<=n;++i)
{
for(j=1;j<=n;++j)
{
if(a[i][j]>a[i][k]+a[k][j])
{
/*修改路径长度*/
a[i][j]=a[i][k]+a[k][j];
/*修改路径*/
path[i][j]=path[i][k];
}
}
}
}
}
 
/*判断是否是负权回路*/
int isNegationLoop(int n)
{
int i,j,k;
for(k=1;k<=n;++k)
{
for(i=1;i<=n;++i)
{
for(j=1;j<=n;++j)
{
/*如果存在顶点k,从i到j存在一条更短的路径,则构成负权回路*/
if(a[i][j]>a[i][k]+a[k][j])
{
return 0;
}
}
}
}
return 1;
}
 
/*打印各对顶点的路径情况*/
void Print(int n)
{
int i,j,next;
for(i=1;i<=n;++i)
{
for(j=1;j<=n;++j)
{
/*naxt为path的后续顶点*/
next=path[i][j];
if(next==-1)
{
printf("%d - %d no path/n",i,j);
}
else
{
/*每对顶点i、j的路径长度*/
printf("%d ",a[i][j]);
printf("%d ",i);
while(next!=j)
{
printf("-> %d ",next);
/*继续找下一后续顶点*/
next=path[next][j];
}
printf("-> %d/n",j);
}
}
}
}
 
int main()
{
int n,i,j,x,y,value;
scanf("%d",&n);
/*初始化c*/
for(i=0;i<=n;++i)
{
for(j=0;j<=n;++j)
{
if(i==j)
{
c[i][j]=0;
}
else
{
c[i][j]=MAX;
}
}
}
while(1)
{
/*读入权值*/
scanf("%d%d%d",&x,&y,&value);
if(x==0&&y==0&&value==0)
{
break;
}
c[x][y]=value;
}
Floyd(n);
if(isNegationLoop(n))
{
Print(n);
}
else
{
printf("the short loop isn't exit/n");
}
system("pause");
return 0;
}
原创粉丝点击