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次)

posted @ 2012-08-05 21:57  pushing my way  阅读(413)  评论(0编辑  收藏  举报