##算法功能
找最短路(最长路?)
##算法思想
用一个节点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 }
来源:https://www.cnblogs.com/ZhengkunJia/p/12213249.html