您的位置:首页 > 其它

【算法系列学习】SPFA邻接表最短路 [kuangbin带你飞]专题四 最短路练习 F - Wormholes

2017-04-07 21:44 661 查看
https://vjudge.net/contest/66569#problem/F

题意:判断图中是否存在负权回路

首先,介绍图的邻接表存储方式

数据结构:图的存储结构之邻接表

邻接表建图,类似于头插法建单链表

head[x]:以x为源点的第一条边,初始值为-1.

struct edge

{

  int to;

  int weight;

  int next;
}e[maxn];

to表示被指向的点;weight表示这条边的权重;next表示源点同为x的下一条边,这是遍历以x为源点的的关键

SPFA算法中的队列与BFS不同的是,每个点都可以在重复进入队列,而且进入队列总次数大于顶点总数说明该图存在负环。这是因为每个点的估计最短路可能在出队列后被更新,这样这个点就可以再次进入队列去更新其他点。

1 #include<iostream>
2 #include<cstdio>
3 #include<string>
4 #include<cstring>
5 #include<cmath>
6 #include<algorithm>
7 #include<queue>
8 using namespace std;
9 const int maxn=5205;
10 const int inf=0x3f3f3f3f;
11 int n,m,w;
12 struct edge
13 {
14     int to;
15     int time;
16     int next;
17 }e[maxn];
18 int head[505];
19
20 int Spfa(int src)
21 {
22     //记录每个顶点到src的距离,除了src,其余点都初始化为无穷大
23     int dis[505];
24     memset(dis,inf,sizeof(dis));
25     dis[src]=0;
26     //记录每个顶点进入队列的总次数,大于n说明有负环
27     int cnt[505];
28     memset(cnt,0,sizeof(cnt));
29     //记录是否在队列中
30     bool inque[505];
31     memset(inque,0,sizeof(inque));
32     queue<int> Q;
33     //源点进如队列
34     Q.push(src);
35     inque[src]=1;
36     cnt[src]++;
37     while(!Q.empty())
38     {
39         int q=Q.front();
40         Q.pop();
41         //记录已经出队列
42         inque[q]=0;
43         //邻接表,i表示边
44         for(int i=head[q];i!=-1;i=e[i].next)
45         {
46             //对每个点进行松弛,逐渐逼近最小值
47             if(dis[q]+e[i].time<dis[e[i].to])
48             {
49                 dis[e[i].to]=dis[q]+e[i].time;
50                 //如果更新成功而且当前不在队列中,进入队列且总次数加1
51                 if(!inque[e[i].to])
52                 {
53                     inque[e[i].to]=1;
54                     cnt[e[i].to]++;
55                     Q.push(e[i].to);
56                     //说明存在负环
57                     if(cnt[e[i].to]>n)
58                     {
59                         return 1;
60                     }
61                 }
62             }
63         }
64     }
65     return 0;
66 }
67 int main()
68 {
69     int T;
70     scanf("%d",&T);
71     int x,y,t;
72     while(T--)
73     {
74         memset(head,-1,sizeof(head));
75         scanf("%d%d%d",&n,&m,&w);
76         int tot=0;
77         for(int i=1;i<=m;i++)
78         {
79             scanf("%d%d%d",&x,&y,&t);
80             e[tot].to=y;
81             e[tot].time=t;
82             e[tot].next=head[x];
83             head[x]=tot++;
84             e[tot].to=x;
85             e[tot].time=t;
86             e[tot].next=head[y];
87             head[y]=tot++;
88         }
89         for(int i=1;i<=w;i++)
90         {
91             scanf("%d%d%d",&x,&y,&t);
92             e[tot].to=y;
93             e[tot].time=-t;
94             e[tot].next=head[x];
95             head[x]=tot++;
96         }
97         int ans=Spfa(1);
98         if(ans==1)
99         {
100             puts("YES");
101         }
102         else
103         {
104             puts("NO");
105         }
106     }
107     return 0;
108  }


邻接表+SPFA
理论上以任意一点为源点都是可以的,顶点的数据范围是1~N,所以Spfa(1)或Spfa(n)都可以AC,其他的具体值不可以
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐