##算法功能
找最短路(最长路?)
##算法思想
用一个节点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