您的位置:首页 > 其它

最短路 Bellman-Ford 边上权值任意的单源最短路

2012-08-16 19:03 435 查看
小B算法:

怎样都好,就是不能图中包含负权值回路。。!

假如图中有n个点,那么我们需要将图遍历(因为有n-1条边)n-1次(邻接表)或n-2(邻接矩阵,因为有初始化),每次遍历的时候,拿出一个点(u),再与其他个点比较(v),如果起始点到u距离大于 起始点到v的距离加上u到v的距离,那么就更新。直到所有的点拿完,再去遍历吧。。

判断存在负权值回路方法:

遍历完n-1边以后,我们在更新一次所有点,如果还能更改,那么一定存在负权值回路。

*做了一些题,发现这个算法用于判断回路比较多,比如负权值回路与正权值回路。也可以结合flody算法来用,flody算法判断两点关系,是否可到达。然后在来用bellman-ford判断回路求解。如果在点i j存在回路,i到n可达,那么balabala....之类的用法。

code:

邻接矩阵 时间复杂度 O(n3)

#include<stdio.h>
#include<string.h>
#define MX 100000
int n,m,map[100][100],path[100],dist[100];
void bellman(int v0)
{
for(int i=0;i<n;i++)
{
dist[i]=map[v0][i];
if(map[v0][i]<MX)
path[i]=v0;
else
path[i]=-1;
}
dist[v0]=0;
for(int i=0;i<n-2;i++)       //遍历n-2遍
{
for(int j=0;j<n;j++)   //拿出一个点
{
if(j!=v0)
{
for(int k=0;k<n;k++)  //在拿出另外一个点,开始更新
{
if(map[k][j]<MX&&dist[k]+map[k][j]<dist[j])
{
path[j]=k;
dist[j]=dist[k]+map[k][j];
}
}
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
map[i][j]=MX;
for(int i=0;i<m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
map[a][b]=c;
}
bellman(0);
int pa[100];
for(int i=0;i<n;i++)
{
printf("%d\n",dist[i]);
int now=i,k=1;
pa[0]=i;
while(path[now]!=-1)
{
pa[k]=path[now];
now=path[now];
k++;
}
for(int j=k-1;j>0;j--)
printf("%d ->",pa[j]);
printf("%d\n",pa[0]);
}
}
return 0;
}
邻接表判断有负权值回路

for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
if(map[j][i]<MX&&dist[j]+map[j][i]<dist[i])
return false;  //有负环回路
}
return true;  //没有负环回路


邻接表 时间复杂度 O(nm)

#include<stdio.h>
#include<string.h>
#define MX 1000000
int n,m,dist[100],path[100];
struct point
{
int u,v,w;
}eg[100];
void bellman(int v0)
{
for(int i=0;i<n;i++)
{
path[i]=-1;
dist[i]=MX;
}
dist[v0]=0;
for(int i=0;i<n-1;i++)
{
for(int j=0;j<m;j++)
{
if(dist[eg[j].u]<MX&&dist[eg[j].u]+eg[j].w<dist[eg[j].v])
{
dist[eg[j].v]=dist[eg[j].u]+eg[j].w;
path[eg[j].v]=eg[j].u;
}
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
for(int i=0;i<m;i++)
scanf("%d%d%d",&eg[i].u,&eg[i].v,&eg[i].w);
bellman(0);
for(int i=1;i<n;i++)
{
int now=i,k=1;
int pa[100];pa[0]=i;
printf("%d\n",dist[i]);
while(path[now]!=-1)
{
pa[k]=path[now];
now=path[now];
k++;
}
for(int j=k-1;j>0;j--)
printf("%d->",pa[j]);
printf("%d\n",pa[0]);
}
}
return 0;
}
邻接表判断负环回路

for(int i=0;i<m;i++)
{
if(dist[eg[i].u]+eg[i].w<dist[eg[i].v])
return false;   //存在
}
return true;  //不存在负环回路
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: