【算法】Bellman-Ford算法(单源最短路径问题)(判断负圈)
单源最短路问题是固定一个起点,求它到其他所有点的最短路的问题。
算法:
设 d[i] 表示 起点 s 离点 i 的最短距离。
【1.初始化】 固定起点s,对所有的点 , 如果 i = s , d[i] 置为 0 ;如果 i != s , d[i] 置为 INF,执行 2。
【2.更新】 update = false。 用所有的边更新所有的点离源点的距离,update = true。
如果更新过update = true,重复执行2 ; 如果没有更新过update = false, 执行3。
【3.输出】 打印 d 数组中所求的结果。
代码:
#include <bits\stdc++.h> using namespace std; #define INF 2147483647 #define MAX_V 1000 #define MAX_E 2000 // 单源最短路径1(Bellman-Ford算法) struct edge{ int from,to,cost; }; edge es[MAX_E]; //所有的边 int d[MAX_V]; //d[i]表示源点到i点的最短距离 int V,E; //V是顶点数,E是边数 //求解从s离所有点的距离 void shortest_path(int s){ for(int i = 0;i < V; i++) d[i] = INF; d[s] = 0; //用可到达的点和从这个点出发的边更新这条边到达的点与源点的距离。 //如果无点可更新,则跳出 while(true){ bool update = false; for(int i = 0;i < E; i++){ edge e = es[i]; if(d[e.from] != INF && d[e.to] > d[e.from] + e.cost){ d[e.to] = d[e.from] + e.cost; update = true; } } if(!update) break; } } int main(){ }
负圈:负圈又称负环,就是说一个全部由负权的边组成的环,这样的话不存在最短路,因为每在环中转一圈路径总长就会变小。
Bellman-Ford算法求最短路径不会经过同一个点两次。如果不存在负圈的话最多会更新 V-1 次,即每次只更新出一个点(想象一下线性存储的情况)。
如果有负圈的话会无限更新下去。
所以判断负圈是否存在只用判断是否更新了大于V-1次即可。
代码:
#include <bits\stdc++.h> using namespace std; #define INF 2147483647 #define MAX_V 1000 #define MAX_E 2000 // 单源最短路径1(Bellman-Ford算法) struct edge{ int from,to,cost; }; edge es[MAX_E]; //所有的边 int d[MAX_V]; //d[i]表示源点到i点的最短距离 int V,E; //V是顶点数,E是边数 //判断是否存在负圈 bool find_negative_loop(){ memset(d,0,sizeof(d)); for(int i = 1;i <= V; i++){ for(int j = 0;j < E; j++){ edge e = es[j]; if(d[e.to] > d[e.from] + e.cost){ d[e.to] = d[e.from] + e.cost; //如果更新了V次说明存在负圈 if(i == V) return true; } } } return false; } int main(){ }