您的位置:首页 > 其它

单源最短路径——Bellman--Ford算法

2015-07-13 20:24 253 查看
Bellman--Ford算法可以处理路径权值为负数的单源最短路径问题。

时间复杂度  o(n*m)

    设想可以从图中找到一个环路,且这个环路中所有路径的权值之和为负。那么通过这个环路,环路中任意两点的最短路径就可以无穷小下去。如果不处理这个负环路,程序就会永远运行下去。而Bellman--Ford算法具有分辨这种负环路的能力。

基本算法:

    Bellman--Ford算法基于动态规划,反复用已有的边来更新最短距离,Bellman--Ford算法的核心思想是松弛。如果dist[u]和dist[v]满足dist[v]<=dist[u]+map[u][v],dist[v]就应该被更新为dist[u]+map[u][v]。反复地利用上式对dist数组进行松弛,如果没有负权回路的话,应当会在n-1次松弛之后结束。原因在于考虑对每条边进行1次松弛的时候,得到的实际上是至多经过0个点的最短路径,对每条边进行两次松弛的时候得到的是至多经过1个点的最短路径,如果么有负权回路,那么任意两点间的最短路径至多经过n-2个点,因此经过n-1次松弛操作后应当可以得到最短路径。如果有负权回路,那么第n次松弛操作仍然会成功,Bellman-Ford算法就算利用这个性质判定负环。

//Bell-Ford可以处理路径权值为负数时的单源最短路径问题,时间复杂度为o(n*m).
//根据HDU1874
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define maxn 1010
#define INF 0x3f3f3f3f
int n,m,a,b,c,s,e,sum,k,k1;
int map[maxn][maxn],pre[maxn],dist[maxn],lj[maxn];
struct stu
{
int from,to,w;
}p[maxn];

void add(int x,int y,int w)
{
p[sum].from=x;
p[sum].to=y;
p[sum++].w=w;
}

void bellman(int s,int e)
{
for(int i=0;i<=n;i++)
{
dist[i]=INF;
pre[i]=s;
}
pre[s]=-1;
dist[s]=0;
for(int i=0;i<n-1;i++)
{
for(int j=0;j<sum;j++)
{
int u=p[j].from;
int v=p[j].to;
int w=p[j].w;
if(dist[v]>dist[u]+w)
{
dist[v]=dist[u]+w;
pre[v]=u;
}
}
}
// for(int j=0;j<sum;j++)
// {
// int u=edge[j].from;
// int v=edge[j].to;
// int w=edge[j].w;
// if(dist[u]>dist[u]+w)
// return false;
// }
// return true;
}
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]=map[j][i]=INF;
memset(lj,0,sizeof(lj));
sum=0;
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
if(c<map[a][b])
{
map[a][b]=map[b][a]=c;
add(a,b,c);
add(b,a,c);
}
}
scanf("%d%d",&s,&e);
bellman(s,e);
k=e;
k1=0;
lj[k1++]=e;
while(pre[k]!=-1)
{
lj[k1++]=pre[k];
k=pre[k];

}

printf("%d",s);
for(int i=k1-2;i>=0;i--)
printf("->%d",lj[i]);
printf("\n");

if(dist[e]==INF)
printf("-1\n");
else
printf("%d\n",dist[e]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: