zoukankan      html  css  js  c++  java
  • 最短路—SPFA

    求单源最短路的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 }
  • 相关阅读:
    Linux Shell 01 脚本与变量
    Linux下shell颜色配置
    Linux下Redis安装及配置
    Linux Shell 03 条件测试
    OSX下VirtualBox安装CentOS
    Log4j配置与使用
    Linux 环境变量的配置
    OS X下安装Redis及配置开机启动
    圈复杂度
    (转)Qt Model/View 学习笔记 (一)——Qt Model/View模式简介
  • 原文地址:https://www.cnblogs.com/pony1993/p/2616271.html
Copyright © 2011-2022 走看看