求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm。
SPFA算法是西南交通大学段凡丁于1994年发表的.
很多时候,给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了。
    我们用数组d记录每个结点的最短路径估计值,而且用邻接表来存储图G。
我们采取的方法是动态逼近法:设立一个先进先出的队列用来保存待优化的结点,优化时每次取出队首结点u,并且用u点当前的最短路径估计值对离开u点所指向的结点v进行松弛操作,如果v点的最短路径估计值有所调整,且v点不在当前的队列中,就将v点放入队尾。
这样不断从队列中取出结点来进行松弛操作,直至队列空为止。
   定理: 只要最短路径存在,上述SPFA算法必定能求出最小值。
    期望的时间复杂度O(ke), 其中k为所有顶点进队的平均次数,可以证明k一般小于等于2。 
    实现方法:建立一个队列,初始时队列里只有起始点,再建立一个表格记录起始点到所有点的最短路径(该表格的初始值要赋为极大值,该点到他本身的路径赋为0)。然后执行松弛操作,用队列里有的点去刷新起始点到所有点的最短路,如果刷新成功且被刷新点不在队列中则把该点加入到队列最后。

重复执行直到队列为空

判断有无负环:如果某个点进入队列的次数超过N次则存在负环(SPFA无法处理带负环的图)

模版:

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 typedef struct node
 6 {
 7     long adj,data;/*adj为邻接点,data为边的权值*/
 8     struct node *next;
 9 }node;
10 node *g[1000];
11 long dis[1000],flag[1000],q[1000],n,e;/*dis记录最短路径值,flag做出入队标记,q为队列*/
12 void spfa(long st)
13 {
14     long i,k,front,rear;
15     node *p;
16     for(i=0;i<n;i++) 
17         dis[i]=0x7fffffff;/*初始化路径为长整型最大数*/
18     memset(flag,0,sizeof(flag));/*入队标记初始化为0*/
19     front=0;
20     rear=1;
21     /*将起始点入队*/
22     dis[st]=0;/*到自己距离为0*/
23     q[rear]=st;/*入队*/ 
24     flag[st]=1;/*置入队标记*/
25     while(front!=rear)/*当队列不为空时*/
26     {     
27         front=(front+1)%1000;/*出队,注意使用循环队列*/
28         k=q[front];/*记下出队点号*/
29         flag[k]=0;/*置出队标记*/
30         p=g[k];/*找到以出队点为头的邻接链表,考察由出队点中转至各邻接点路径是否更短*/
31         while(p)
32         {
33             if(dis[k]+p->data<dis[p->adj])
34             { 
35                 dis[p->adj]=dis[k]+p->data;/*路径更短,更新路径值*/
36                 if(!flag[p->adj])/*若其邻接点未入队*/
37                 { 
38                     rear=(rear+1)%1000;/*入队*/
39                     q[rear]=p->adj;
40                     flag[p->adj]=1;/*置入队标记*/
41                 }
42             }
43             p=p->next;/*记得改变循环变量,考察下一个邻接点*/
44         }
45     }  
46 }
47 int main()
48 {
49     long i,x,y,z;
50     node *p;
51     scanf("%ld%ld",&n,&e);/*读入点数,边数*/
52     memset(g,0,sizeof(g));/*初始化图*/
53     for(i=1;i<=e;i++)/*读入边的信息,左点、右点、权值*/
54     {
55         scanf("%ld%ld%ld",&x,&y,&z);
56         p=(node*)malloc(sizeof(node));/*创建链表*/
57         p->data=z;
58         p->adj=y;
59         p->next=g[x];/*尾插法*/
60         g[x]=p;
61     }
62     spfa(0);/*计算由起始点到各点的最短路径*/
63     for(i=0;i<n;i++)
64         printf("%ld ",dis[i]);
65     printf("\n");
66     return 0;
67 }

 

POJ 3259

 

View Code
  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cstdio>
  5 #include <queue>
  6 using namespace std;
  7 
  8 const int N=501;
  9 const int NN=100001;
 10 const int inf=0x7fffffff;
 11 queue<int> qu;
 12 int n,nu;
 13 
 14 typedef struct node
 15 {
 16     int adj,val;
 17     struct node *next;
 18 }node;
 19 node node[NN],*p[N];
 20 
 21 int SPFA()
 22 {
 23     int x,i,a,b;
 24     int vis[N],dis[N],num[N];
 25     struct node *head[N];
 26     for(i=1;i<=n;i++)
 27     {
 28         vis[i]=0;
 29         num[i]=0;
 30         dis[i]=inf;
 31         head[i]=p[i];
 32     }
 33     dis[1]=0;
 34     vis[1]=1
 35     num[1]++;
 36     qu.push(1);
 37     while(!qu.empty())
 38     {
 39         x=qu.front();
 40         qu.pop();
 41         vis[x]=0;
 42         head[x]=p[x];
 43         while(head[x])
 44         {
 45             a=head[x]->adj;
 46             b=head[x]->val;
 47             if(dis[a]>dis[x]+b)
 48             {
 49                 dis[a]=dis[x]+b;
 50                 if(!vis[a])
 51                 {
 52                     qu.push(a);
 53                     vis[a]=1;
 54                     num[a]++;
 55                     if(num[a]>=n)//如果入队的次数超过总数,说明存在回路 
 56                         return 1;
 57                 }
 58             }
 59             head[x]=head[x]->next; 
 60         }
 61     }
 62     return 0;
 63 }
 64 
 65 int main()
 66 {
 67     int t,i,m,w,a,b,c;
 68     scanf("%d",&t);
 69     while(t--)
 70     {
 71         while(!qu.empty()) 
 72             qu.pop();
 73         memset(node,0,sizeof(node));
 74         memset(p,0,sizeof(p));
 75         nu=0;
 76         scanf("%d%d%d",&n,&m,&w);
 77         for(i=0;i<m;i++)
 78         {
 79             scanf("%d%d%d",&a,&b,&c);
 80             node[nu].adj=b;  
 81             node[nu].val=c;
 82             node[nu].next=p[a];  
 83             p[a]=&node[nu];  
 84             nu++;  
 85             node[nu].adj=a;  
 86             node[nu].val=c;  
 87             node[nu].next=p[b];  
 88             p[b]=&node[nu];  
 89             nu++; 
 90         }
 91         for(i=0;i<w;i++)
 92         {
 93             scanf("%d%d%d",&a,&b,&c);
 94             node[nu].adj=b;  
 95             node[nu].val=-c;
 96             node[nu].next=p[a];
 97             p[a]=&node[nu];  
 98             nu++;  
 99         }
100         if(SPFA()) 
101             puts("YES");
102         else 
103             puts("NO");
104     }
105     return 0;
106 }

 

 

 

 

posted on 2012-07-31 09:29  pony1993  阅读(378)  评论(0编辑  收藏  举报

View My Stats