洛谷P3385 【模板】負環node
模板題沒人發題解嘛??大概是太簡單了dalao們不屑於發吧(大霧,輕噴)c++
確實很模板,題意清晰明瞭,下面給出\(Bellman-Ford\)算法斷定負環和\(SPFA\)斷定負環這兩種作法的講解qwq算法
(爲了學好差分約束來的)spa
當執行更新\(dis[v]=dis[x]+e[i].val\)時,同時更新\(cnt[v]=cnt[x]+1\).net
若發現\(cnt[v]≥n\),則說明圖中又負環;若算法正常結束,則說明圖中沒有負環code
當執行更新\(dis[v]=dis[x]+e[i].val\)時,同時更新\(cnt[v]++\)get
若\(cnt[v]==n\)則說明有負環it
《算法競賽進階指南》上說第一種方法比第二種方法高效:由於第一種方法只須要繞環一次就能發現負環,而斷定入隊次數的作法須要繞環\(n\)次模板
\(However\),我針對於這兩種方法都交上去評測,結果大出意料:第二種方法成功AC,而後第一種方法只有\(10pts\)!(大概是我沒編對?若是您作出來可以AC,能否麻煩您貼一下代碼,謝謝啊qwq)class
#include <bits/stdc++.h> using namespace std; queue<int> q; int T,n,m,u,v,w; int tot,dis[60010],vis[60010],cnt[60010],head[60010]; struct node { int to,net,val; } e[60010]; inline void add(int u,int v,int w) { e[++tot].to=v; e[tot].val=w; e[tot].net=head[u]; head[u]=tot; } inline bool spfa() { for(register int i=1;i<=n;i++) { vis[i]=0; cnt[i]=0; dis[i]=20050206; } dis[1]=0; vis[1]=0; cnt[1]++; q.push(1); while(!q.empty()) { int x=q.front(); q.pop(); vis[x]=0; for(register int i=head[x];i;i=e[i].net) { int v=e[i].to; if(dis[v]>dis[x]+e[i].val) { if(cnt[v]>=n-1) return true; //斷定入隊次數 dis[v]=dis[x]+e[i].val; if(!vis[v]) { cnt[v]++; vis[v]=1; q.push(v); } } } } return false; } int main() { scanf("%d",&T); while(T--) { tot=0; for(register int i=1;i<=n;i++) { e[i].to=0; e[i].val=0; e[i].net=0; head[i]=0; } scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); add(u,v,w); if(w>=0) add(v,u,w); } if(spfa()==false) puts("NO"); else puts("YES"); } return 0; }
若通過\(n\)輪迭代,算法仍未結束(仍有能產生更新的邊),則圖中存在負環
若\(n-1\)輪迭代以內,算法結束(全部邊都知足三角形不等式),則圖中無負環
本題須要注意一點的是:題目要求找到一個 \(1\)能到達的負環
而輸入並不保證\(1\)必定與其餘點連通!即\(1\)多是一個「孤兒點」(#11就是一個例子QAQ)
#include <bits/stdc++.h> using namespace std; int T,n,m,u,v,w,tot,flag,dis[600010]; struct node { int to,fro,val; } e[600010]; inline void add(int u,int v,int w) { e[++tot].to=v; e[tot].fro=u; e[tot].val=w; } inline bool ford() { for(register int i=1;i<=n;i++) dis[i]=2005020600; dis[1]=0; for(register int i=1;i<n;i++) { for(register int j=1;j<=tot;j++) { if(dis[e[j].fro]+e[j].val<dis[e[j].to]) { dis[e[j].to]=dis[e[j].fro]+e[j].val; } } } for(register int i=1;i<=tot;i++) { if(dis[e[i].fro]+e[i].val<dis[e[i].to]) return true; } return false; } int main() { scanf("%d",&T); while(T--) { tot=0;flag=0; scanf("%d%d",&n,&m); for(register int i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&w); if(u==1||v==1) flag=1; add(u,v,w); if(w>=0) add(v,u,w); } if(flag==0) { puts("NO"); continue; } if(ford()==false) puts("NO"); else puts("YES"); } return 0; }
最後,若是您有任何不懂或這篇題解有任何不對的地方,歡迎評論區指出,我會及時回覆、改正,謝謝各位dalao閱讀qwq