最短路——spfa算法

##算法功能

  找最短路(最长路?)

##算法思想

  用一个节点k更新节点i到节点j的最短路

##邻接链表存储

  基础而高效的图的存储方式

  存的是单向边(无向边可以看成两条有向边)

##实现

  维护节点i到源点s的最小值d[i]

  用队列实现

    维护队列z,

      用visit[]记录一个点是否在队列

    从源点开始进队列,每次弹出队头元素x,(标记visit[x]=0)

    用它的最短路d[x]将与它相连的节点y的最短路d[y]更新

    如果y不在队列(visit[y]==0),让y入队,记录(visit[y]=1)

    直到队列为空,所有节点的d[]都已维护好

##判断负环

  若图中存在负环,则更新时一定不断地让负环上的节点入队,负环上的点一定会无数次入队,最终死循环

  所以我们记录一个点入队的次数sum[],sum[i]在每次i入队时++,如果sum[i]贼大,贼大,证明有负环

    贼大到多大呢?贼大到2*m(m是边数)就肯定死循环了

    反正就是不能比2*m大(一共m条边,假设都与节点i相连,则i最多入队m次(当然不可能所有边都让i走一遍)(老师让sum[i]和m*2比较,不知道为啥那么大

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <string>
 5 #include <cstring>
 6 #include <cmath>
 7 #include <queue>
 8 #define N 100010
 9 #define M 100010
10 //复杂度上限m*n
11 //n个点,每个如m次 
12 
13 //正常nlogn
14 
15 //网格图贼慢 
16 using namespace std;
17 
18 queue <int> z;
19 int d[N],len,visit[N],n,m;
20 
21 //采用结构体存图 
22 struct edge
23 {
24     int x,y,k,next;
25 }a[M];
26 // 邻接链表存储 
27 int first[M];
28 void ins(int x,int y,int k)
29 {
30     len++;
31     a[len].x=x;
32     a[len].y=y;
33     a[len].k=k;
34     a[len].next=first[x];
35     first[x]=len;
36 }
37 int sum[N];
38  
39 int main()
40 {
41     cin>>n>>m;
42     memset(d,63,sizeof(d));//63是billion(十亿)级别的10 6110 9567 
43     int x,y,k;
44     for(int i=1;i<=m;i++)
45     {
46         cin>>x>>y>>k;
47         ins(x,y,k);
48         ins(y,x,k);
49     }
50     int s;
51     cin>>s;//源点 
52     z.push(s);
53     visit[s]=1;
54     d[s]=0;
55     
56     //******主体代码 
57     while(!z.empty())
58     {
59         x=z.front();
60         for(int k=first[x];k;k=a[k].next)
61         {
62             y=a[k].y;
63             if(d[x]+a[k].k < d[y])
64             {    
65                 d[y]=d[x]+a[k].k;
66                 if(!visit[y])
67                 {
68 //                    sum[y]++;
69                     z.push(y);//这是一个迭代的过程    
70                     visit[y]=1;    
71                 }
72             }
73         }
74         z.pop();
75         sum[x]++;
76         /*if(sum[x] > 2*m)//判断负环 有时会用到 
77         {
78             printf("NO");
79             break;
80         }*/        
81         visit[x]=0;
82     }
83     //********** 
84     for(int i=1;i<=n;i++)    cout<<d[i]<<" ";//得到所有节点到源点的最短路 
85     return 0;
86 }

猜你喜欢

转载自www.cnblogs.com/ZhengkunJia/p/12213249.html