P3385 【模板】负环

题目链接 https://www.luogu.com.cn/problem/P3385

SPFA还没学,先用Bellman-Ford。   //更SPFA——2022.5.2

注意第45行的特判,因为存在某点不连通的情况。(差点没要我命...)


 

Bellman-ford

放AC代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=2e6 + 1000;
 4 int t,n,m;
 5 int cnt;
 6 long long dis[N];
 7 bool vis[N];
 8 
 9 struct Edge
10 {
11     int u,v,w;
12 } edge[N];
13 
14 void add(int u,int v,int w)
15 {
16     edge[++cnt]= {u,v,w};
17 }
18 
19 void addd(int u,int v,int w)
20 {
21     if(w<0) add(u,v,w);
22     if(w>=0) add(u,v,w),add(v,u,w);
23 }
24 
25 bool bellman_ford()
26 {
27     for(int i=1; i<=n; i++)
28     {
29         dis[i]=INT_MAX;
30     }
31     dis[1]=0;
32 
33     for(int i=1; i<n; i++)
34     {
35         for(int j=1; j<=cnt; j++)
36         {
37             if(dis[edge[j].u]!=INT_MAX && dis[edge[j].v]>dis[edge[j].u]+edge[j].w)
38                 dis[edge[j].v]=dis[edge[j].u]+edge[j].w;
39         }
40     }
41 
42     bool flag=1;//标记有无负环
43     for(int i=1; i<=cnt; i++)
44     {
45         if(dis[edge[i].u]==INT_MAX || dis[edge[i].v]==INT_MAX)//存在不连通的节点
46             continue;
47         if(dis[edge[i].v]>dis[edge[i].u]+edge[i].w)//松弛是否成功
48         {
49             flag=0;//成功则有负环
50             break;
51         }
52     }
53     return flag;
54 }
55 
56 int main()
57 {
58     cin>>t;
59     while(t--)
60     {
61         cin>>n>>m;
62         cnt=0;
63         for(int i=1; i<=m; i++)
64         {
65             int u,v,w;
66             cin>>u>>v>>w;
67             addd(u,v,w);
68         }
69         if(bellman_ford())
70             cout<<"NO"<<endl;
71         else
72             cout<<"YES"<<endl;
73     }
74     return 0;
75 }

 

SPFA

放AC代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e3+10;
 4 const int maxm = 6e3+10;
 5 int t,n,m;
 6 int tot;
 7 int head[maxn];
 8 int dis[maxn];
 9 bool vis[maxn];
10 int cnt[maxn];//表示1到i的最短路包含的边数
11 queue<int> q;
12 
13 struct edge
14 {
15     int v,w,next;
16 } edge[maxm];
17 
18 void init()
19 {
20     for(int i=0;i<maxm;i++) edge[i].next=0;
21     for(int i=0;i<maxn;i++) head[i]=0;
22     tot=0;
23 }
24 
25 void add(int u,int v,int w)
26 {
27     edge[++tot].v=v;
28     edge[tot].w=w;
29     edge[tot].next=head[u];
30     head[u]=tot;
31 }
32 
33 bool spfa()
34 {
35     memset(dis,0x3f,sizeof(dis));
36     memset(vis,0,sizeof(vis));
37     memset(cnt,0,sizeof(cnt));
38     dis[1]=0;
39     vis[1]=true;
40     q.push(1);
41     while(!q.empty())
42     {
43         int x=q.front();
44         q.pop();
45         vis[x]=false;
46         for(int i=head[x]; i!=0; i=edge[i].next)
47         {
48             int y=edge[i].v;
49             int z=edge[i].w;
50             if(dis[y]>dis[x]+z)
51             {
52                 dis[y]=dis[x]+z;//更新最短路
53                 cnt[y]=cnt[x]+1;//更新包含边数
54                 if(cnt[y]>=n) return true;
55                 if(!vis[y])
56                 {
57                     q.push(y);
58                     vis[y]=true;
59                 }
60             }
61         }
62     }
63     return false;
64 }
65 
66 int main()
67 {
68     cin>>t;
69     while(t--)
70     {
71         init();
72         cin>>n>>m;
73         for(int i=1; i<=m; i++)
74         {
75             int u,v,w;
76             cin>>u>>v>>w;
77             add(u,v,w);
78             if(w>=0) add(v,u,w);
79         }
80         puts(spfa()?"YES":"NO");
81     }
82     return 0;
83 }

 

posted @ 2022-04-27 17:02  爱吃虾滑  阅读(17)  评论(0编辑  收藏  举报