spfa_队列
spfa:
1.当给定的图存在负权边时,Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了.
2.我们约定有向加权图G不存在负权回路,即最短路径一定存在
3.思路:
用数组d记录每个结点的最短路径估计值,而且用邻接表来存储图G。我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。这样不断从队列中取出结点来进行松弛操作,直至队列空为止。
4.实现方法:
建立一个队列,初始时队列里只有起始点,在建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。重复执行直到队列为空.
代码:
View Code
1 #include <iostream> 2 #include <memory.h> 3 #include <stdio.h> 4 #include <queue> 5 using namespace std; 6 const int maxp=1000; 7 const int maxe=1000; 8 const int maxnum=1000; 9 struct edge 10 { 11 int v; 12 int w; 13 int next; 14 }edge[maxe]; 15 16 typedef struct 17 { 18 int d; 19 int pre; 20 }pp; 21 pp point[maxp]; 22 int p,e; 23 24 queue<int> q; 25 bool use[maxp]; 26 27 void Init() 28 { 29 int i; 30 for(i=1;i<=p;i++) 31 { 32 point[i].d=maxnum; 33 point[i].pre=-1; 34 } 35 int u,v,w; 36 int index=1; 37 for(i=1;i<=e;i++) 38 { 39 cin>>u>>v>>w; 40 edge[index].v=v; 41 edge[index].w=w; 42 edge[index].next=point[u].pre; 43 point[u].pre=index; 44 index++; 45 } 46 } 47 48 void spfa(int s) 49 { 50 memset(use,false,sizeof(use)); 51 point[s].d=0; 52 q.push(s); 53 use[s]=true; 54 int t,i; 55 while(!q.empty()) 56 { 57 t=q.front(); 58 use[t]=false; 59 q.pop(); 60 for(i=point[t].pre;i!=-1;i=edge[i].next) 61 { 62 int v=edge[i].v; 63 int w=edge[i].w; 64 if(point[v].d>point[t].d+w) 65 { 66 point[v].d=point[t].d+w; 67 if(!use[v]) 68 { 69 q.push(v); 70 use[v]=true; 71 } 72 } 73 } 74 } 75 } 76 77 int main() 78 { 79 cin>>p>>e; 80 Init(); 81 spfa(1); 82 int i; 83 for(i=1;i<=p;i++) 84 cout<<i<<" "<<point[i].d<<endl; 85 return 0; 86 } 87 88 /* 89 5 10 90 1 2 10 91 1 3 5 92 2 3 2 93 2 4 1 94 3 2 3 95 3 4 9 96 3 5 2 97 4 5 4 98 5 1 7 99 5 4 6 100 */
5.判断有无负环:如果某个点进入队列的次数超过N次则存在负环 ( 存在负环则无最短路径,如果有负环则会无限松弛,而一个带n个点的图至多松弛n-1次)