Bellman-Ford SPFA算法

适用范围

单源最短路(可判负圈).

原理

Bellman-Ford算法核心思想:动态规划.d[i]的定义为起点s到第i个点的最短距离.刚开始d[i]数组初始化为INF,d[s]=0.然后遍历所有的边,把所有能更新的点更新一遍,能更新的点判定条件为d[to]>d[from]+w(边权),能更新则更新为d[to]=d[from]+w.这种更新方法最多更新V-1次,因为更新n次就能找到由n条边组成的最短路,而图中不存在由V条边组成的最短路(除非存在负环),因此bellman_ford可以判负环.复杂度O(VE)(V点E边).

代码

 1 struct edge{int from,to,cost;};
 2 edge es[MAX];
 3 int d[MAX];
 4 int V,E;
 5 
 6 bool Bellman_Ford(int s) //起点 如果存在负环返回true,否则返回true
 7 {
 8     for(int i=1;i<=V;i++) d[i]=INF_INT; //点从1开始编号
 9     d[s]=0;
10     int cnt=0; //用来数更新多少次
11     while(true)
12     {
13         bool update=false;
14         for(int i=0;i<E;i++)
15         {
16             edge e=es[i];
17             if(d[e.from]!=INF_INT&&d[e.to]>d[e.from]+e.cost)
18             {
19                 d[e.to]=d[e.from]+e.cost;
20                 update=true;
21             }
22         }
23         if(!update||cnt>=V) break;
24         cnt++;
25     }
26     if(cnt>=V) return true;
27     return false;
28 }

扩展

事实上SPFA算法就是在bellman_ford的基础上加个队列优化,也具有判负环的功能.一般复杂度O(ElogV).但这个优化最差复杂度跟bellman_ford一样为O(VE).

 1 typedef pair<int,int> P;
 2 struct edge{int to,cost;};
 3 vector<edge> es[MAX];
 4 bool vis[MAX];
 5 int d[MAX];
 6 int V,E;
 7 
 8 bool SPFA(int s) //s为起点 存在负环返回true,否则返回false
 9 {
10     queue<P> que;
11     for(int i=1;i<=V;i++) d[i]=INF_INT,vis[i]=false; //点编号从1开始
12     d[s]=0;vis[s]=true;
13     que.push(P(s,0));
14     while(que.size())
15     {
16         P p=que.front();que.pop();
17         if(p.second>=V) return true;
18         int x=p.first;
19         vis[x]=false;
20         for(int i=0;i<es[x].size();i++)
21         {
22             edge e=es[x][i];
23             if(d[e.to]>d[x]+e.cost)
24             {
25                 d[e.to]=d[x]+e.cost;
26                 if(!vis[e.to]) que.push(P(e.to,p.second+1));
27             }
28         }
29     }
30     return false;
31 }

 

posted @ 2019-09-08 19:31  VBL  阅读(300)  评论(0编辑  收藏  举报