Bellman-Ford算法

来源:互联网 发布:在线运行js代码 编辑:程序博客网 时间:2024/05/17 20:30

一、算法概述

  • 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 constconst 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: initializefor(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 predecessordistances[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...Nprint_shortest_path(i+1);}} else {cout << "Sorry, a cycle with negative weight exists!";}return 0;}


五、样例

见下图:

输入样例

6 9 11 2 71 3 91 6 142 3 102 4 153 4 113 6 24 5 65 6 9



输出样例

Bellman_Ford calledprint_shortest_path calledThe Path of ( 1, 1 ) is:1 1print_shortest_path calledThe Path of ( 1, 2 ) is:1 2print_shortest_path calledThe Path of ( 1, 3 ) is:1 3print_shortest_path calledThe Path of ( 1, 4 ) is:1 3 4print_shortest_path calledThe Path of ( 1, 5 ) is:1 3 4 5print_shortest_path calledThe Path of ( 1, 6 ) is:1 3 6--------------------------------Process exited with return value 0Press any key to continue . . .




0 0
原创粉丝点击