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

你可能感兴趣的:(SPFA)