洛谷P3385判负环——spfa
题目:https://www.luogu.org/problemnew/show/P3385
两种方法,dfs和bfs;
一开始写的dfs,要把dis数组初值赋成0,这样从一个连着负边的点开始搜;
在一个负环上,一定会有一个点,从它开始绕环走,dis值一直为负,根据这个找环;
但是数据太强了,过不了:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int const MAXN=4005,MAXM=12005; int T,n,m,head[MAXN],ct,dis[MAXN]; bool vis[MAXN],f; struct N{ int to,next,w; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {} }edge[MAXM]; void add(int x,int y,int z) { edge[++ct]=N(y,head[x],z);head[x]=ct; } int rd() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*f; } void dfs(int x) { if(f)return; vis[x]=1; for(int i=head[x],u;i;i=edge[i].next) { u=edge[i].to; if(f)return; if(dis[u]>dis[x]+edge[i].w) { // printf("x=%d u=%d vis[u]=%d\n",x,u,vis[u]); if(vis[u]) { f=1;return; } dis[u]=dis[x]+edge[i].w; dfs(u); if(f)return; } } vis[x]=0;//! } int main() { T=rd(); while(T--) { n=rd();m=rd(); ct=0;f=0; memset(head,0,sizeof head); for(int i=1,x,y,z;i<=m;i++) { x=rd();y=rd();z=rd(); add(x,y,z); if(z>=0)add(y,x,z); } memset(vis,0,sizeof vis); memset(dis,0,sizeof dis); for(int i=1;i<=n;i++) { dfs(i); if(f)break; } if(f)printf("YE5\n"); else printf("N0\n"); } return 0; }
于是用bfs,根据最短路边数来判断,若边数>=n则有负环;
bfs的话还有一种判断方式,是根据被松弛次数,若>=n则有负环,但不如上面那个优;
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; //queue<int>q; int const MAXN=4005,MAXM=12005,inf=4000; int T,n,m,head[MAXN],ct,dis[MAXN],cnt[MAXN],que[MAXN],h,t; bool vis[MAXN]; struct N{ int to,next,w; N(int t=0,int n=0,int w=0):to(t),next(n),w(w) {} }edge[MAXM]; inline void add(int x,int y,int z){edge[++ct]=N(y,head[x],z);head[x]=ct;} inline int rd() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); return x*f; } inline bool spfa() { // while(q.size())q.pop(); memset(que,0,sizeof que);h=0;t=0; memset(dis,0x3f,sizeof dis); memset(cnt,0,sizeof cnt); memset(vis,0,sizeof vis); // q.push(1); vis[1]=1;dis[1]=0;que[t]=1; // while(q.size()) while(h!=t+1) { // int x=q.top();vis[x]=0;q.pop(); int x=que[h++];vis[x]=0; if(h==inf)h=0; for(int i=head[x],u;i;i=edge[i].next) if(dis[u=edge[i].to]>dis[x]+edge[i].w) { cnt[u]=cnt[x]+1; if(cnt[u]>=n)return 1; dis[u]=dis[x]+edge[i].w; // if(!vis[u])vis[u]=1,q.push(u); if(!vis[u]) { vis[u]=1; t++; if(t==inf)t=0; que[t]=u; } } } return 0; } int main() { T=rd(); while(T--) { n=rd();m=rd(); ct=0; memset(head,0,sizeof head); for(int i=1,x,y,z;i<=m;i++) { x=rd();y=rd();z=rd(); add(x,y,z); if(z>=0)add(y,x,z); } if(spfa())printf("YE5\n"); else printf("N0\n"); } return 0; }