有向图单源最短路径之Bellman-Ford算法

        Dijkstra算法是处理单源最短路径的有效算法,但它局限于边的权值非负的情况,若图中出现权值为负的边,Dijkstra算法就会失效,求出的最短路径就可能是错的。这时候,就需要使用其他的算法来求解最短路径,Bellman-Ford算法就是其中最常用的一个。该算法由美国数学家理查德•贝尔曼(Richard Bellman, 动态规划的提出者)和小莱斯特•福特(Lester Ford)发明。

适用条件&范围

1.单源最短路径(从源点s到其它所有顶点v); 2.有向图&无向图(无向图可以看作(u,v),(v,u)同属于边集E的有向图); 3.边权可正可负(如有负权回路输出错误提示); 4.差分约束系统;
Bellman-Ford算法描述: 1,.初始化:将除源点外的所有顶点的最短距离估计值 d[v] ←+∞, d[s] ←0; 2.迭代求解:反复对边集E中的每条边进行松弛操作,使得顶点集V中的每个顶点v的最短距离估计值逐步逼近其最短距离;(运行|v|-1次) 3.检验负权回路:判断边集E中的每一条边的两个端点是否收敛。如果存在未收敛的顶点,则算法返回false,表明问题无解;否则算法返回true,并且从源点可达的顶点v的最短距离保存在 d[v]中。
具体的算法流程如下: Bellman-Ford(G,w,s) :boolean   //图G ,边集 函数 w ,s为源点

1        for each vertex v ∈ V(G) do        //初始化 1阶段

2            d[v] ←+∞

3        d[s] ←0;                             //1阶段结束

4        for i=1 to |v|-1 do               //2阶段开始,双重循环。

5           for each edge(u,v) ∈E(G) do //边集数组要用到,穷举每条边。

6              If d[v]> d[u]+ w(u,v) then      //松弛判断

7                 d[v]=d[u]+w(u,v)               //松弛操作   2阶段结束

8        for each edge(u,v) ∈E(G) do

9            If d[v]> d[u]+ w(u,v) then

10            Exit false

11    Exit true

测试用例:

《有向图单源最短路径之Bellman-Ford算法》

实现:

#include <stdio.h>


typedef struct Edge
{
	int a;
	int b;
	int weight;
} Edge;

#define MAX 0x3f3f3f3f
#define MAX_EDGE_NUM 50
#define N 1000
Edge edge[MAX_EDGE_NUM];
int dist[N],pre[N];

bool BellmanFord(int v,Edge edge[],int vertexnum,int edgenum,int dist[],int pre[])
{
	/* negative cycle detected return false */
	int i,j;
	for(i=0;i<vertexnum;i++)
	{
		if (i != v)
			dist[i] = MAX;
		else
			dist[i] = 0;
		pre[i] = v;
	}
	for(i=1;i<=vertexnum;i++)
		for(j=0;j<edgenum;j++)
		{
			/* 松弛n次,每次按照边的相同顺序;第n(vertexnum)次检测负环*/
			if(dist[edge[j].b] > dist[edge[j].a] + edge[j].weight){
				if (i == vertexnum)
					return false;
				dist[edge[j].b] = 
					dist[edge[j].a] + edge[j].weight;
				pre[edge[j].b] = edge[j].a;
			}			
		}
	return true;
} 

void print_path(int v,int pre[],int n)
{
	int i,j;
	for(i=0;i<n;i++)
	{
		j = i;
		printf("%d<-",j);
		while(pre[j] != v)
		{
			printf("%d<-",pre[j]);
			j = pre[j];
		};
		printf("%d\n",v);
	}
}
int main()
{
	int a,b,weight,vertexnum,edgenum;
	scanf("%d%d",&vertexnum,&edgenum);
	for(int i=0;i<edgenum;i++)
	{
		scanf("%d%d%d",&edge[i].a,&edge[i].b,&edge[i].weight); 
	}
	BellmanFord(0,edge,vertexnum,edgenum,dist,pre);
	
	for(int i=0;i<vertexnum;i++)
		printf("%d  ",dist[i]);
	printf("\n");
	
	for(int i=0;i<vertexnum;i++)
		printf("%-3d",pre[i]);
	printf("\n");
	
	print_path(0,pre,5);
}

输入:

5 6
0 4 2
4 3 4
4 1 5
1 3 -2
2 1 -3
3 2 6

输出:

0  7  11  5  2  
0  4  3  1  0  
0<-0
1<-4<-0
2<-3<-1<-4<-0
3<-1<-4<-0
4<-0

REF:

1,算法技术手册George T.Heineman

2,http://www.cnblogs.com/Jason-Damon/archive/2012/04/21/2460850.html

3,http://blog.csdn.net/niushuai666/article/details/6791765

    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/flyapy/article/details/35801999
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞