Bellman-Ford算法

一、算法概述

  • Bellman-Ford算法,也可以翻译成中文“贝尔曼-福特算法”,常常拿来和Dijkstra算法一起比较理解。
  • Bellman-Ford算法的原理是对图进行 V-1 次松弛操作,算法的复杂度高达O(VE)。但是相对于Dijkstra算法,尽管算法复杂度稍高一些,但是它能处理带负权值边而没有负权回路的图。V-1次松弛操作,必定能求出最短路径,因为图的深度最多为V-1.

二、实现步骤

  • 数组 distance[v] 表示从源点source到顶点v的最短路径,即为要求的答案。
  • 数组 predecessor[v] 表示从源点source到顶点v的最短路径p(s,….,v),顶点v的前一个节点。可以由此数组导出一个前驱子图或以source为根的最短路径树。
  • w表示边 (u,v) 的权值。
  1. 初始化操作:一开始从source到自己的距离为0,到其他所有点的最短距离为正无穷大。
  2. 进行 V-1 次松弛操作:每一次对所有的边遍历一遍,若distance[u] + w < distance[v],则更新distance[v]和predecessor[v]。
  3. 检查是否存在负权回路:对每条边遍历一遍,若仍然可以更新distance,说明存在负权回路。

三、伪代码实现

摘自维基百科的贝尔曼-福特算法中文词条。其中的过程可以改写成带布尔型变量返回值的函数。若存在负权回路,则返回false,否则返回true。distance和predecessor可以设置为全局变量。

procedure BellmanFord(list vertices, list edges, vertex source)
   // 该实现读入边和节点的列表,并向两个数组(distance和predecessor)中写入最短路径信息

   // 步骤1:初始化图
   for each vertex v in vertices:
       if v is source then distance[v] := 0
       else distance[v] := infinity
       predecessor[v] := null

   // 步骤2:重复对每一条边进行松弛操作
   for i from 1 to size(vertices)-1:
       for each edge (u, v) with weight w in edges:
           if distance[u] + w < distance[v]:
               distance[v] := distance[u] + w
               predecessor[v] := u

   // 步骤3:检查负权环
   for each edge (u, v) with weight w in edges:
       if distance[u] + w < distance[v]:
           error "图包含了负权环"

四、C++实现

注意这里是有向图的实现。顶点是从1开始的,所以下面的代码中有三处的for循环是从1开始而非0;

/*
 * Bellman-Ford.cpp
 * Author: Halfish Zhang
 * Creat_Time: 5/19/2014
 */

#include <iostream>
#include <stack>
using namespace std;

const int INF_NUM = 0x3f3f3f3f; // momerize this const
const int N = 2014;

struct Edge
{
	int u, v;	// edge (u,v)
	int weight; // the cost(or weight) of edge (u,v)
};

int vertexNum, edgeNum, source;
int distances[N], predecessor[N];
Edge edges[N];

bool Bellman_Ford()
{
	cout << "Bellman_Ford called" << endl;
	// Step One: initialize
	for(int i = 1; i <= edgeNum; ++ i)
	{
		distances[i] = INF_NUM; // you can also use "memset(distances, 0x3f, edgeNum)" to initialize;
		predecessor[i] = i;
	}
	distances[source] = 0;

	// Step Two: relaxation technique, complexity is O(VE)
	for(int i = 1; i <= vertexNum - 1; ++ i)
	{
		for(int j = 0; j < edgeNum; ++ j)
		{
			if(distances[edges[j].v] > distances[edges[j].u] + edges[j].weight)
			{
				// update distances and predecessor
				distances[edges[j].v] = distances[edges[j].u] + edges[j].weight;
				predecessor[edges[j].v] = edges[j].u;
			}
		}
	}

	// Step Three: check if the cycle with nagative weight exists 
	bool flag = true;
	for(int i = 0; i < edgeNum; ++ i)
	{
		if(distances[edges[i].v] > distances[edges[i].u] + edges[i].weight)
		{
			flag = false;
			break;
		}
	}
	return flag;

}

void print_shortest_path(int destination) 
{
	cout << "print_shortest_path called" << endl;
	stack<int> s;
	s.push(destination);

	while(predecessor[s.top()] != source)
	{
		s.push(predecessor[s.top()]);
	}
	s.push(source);

	cout << "The Path of ( " << source << ", " << destination << " ) is: " << endl; 

	int len = s.size();
	for(int i = 0; i < len; ++ i) 
	{
		cout << s.top() << " ";
		s.pop();
	}
	cout << endl;

}

int main(int argc, char const *argv[])
{
	cin >> vertexNum >> edgeNum >> source;
	for(int i = 0; i < edgeNum; ++ i) {
		cin >> edges[i].u >> edges[i].v >> edges[i].weight;
	} 


	if ( Bellman_Ford() ) {
		//test_print();
		for(int i = 0; i < vertexNum; ++ i)
		{
			//attention: edges are numbered 1...N
			print_shortest_path(i+1);
		}
	} else {
		cout << "Sorry, a cycle with negative weight exists!";
	}

	return 0;
}

五、样例

见下图:

《Bellman-Ford算法》

输入样例

6 9 1

1 2 7
1 3 9
1 6 14
2 3 10
2 4 15
3 4 11
3 6 2
4 5 6
5 6 9

输出样例

Bellman_Ford called
print_shortest_path called
The Path of ( 1, 1 ) is:
1 1
print_shortest_path called
The Path of ( 1, 2 ) is:
1 2
print_shortest_path called
The Path of ( 1, 3 ) is:
1 3
print_shortest_path called
The Path of ( 1, 4 ) is:
1 3 4
print_shortest_path called
The Path of ( 1, 5 ) is:
1 3 4 5
print_shortest_path called
The Path of ( 1, 6 ) is:
1 3 6


--------------------------------
Process exited with return value 0
Press any key to continue . . .

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