p3385 【模板】負環(spfa)
阿新 • • 發佈:2018-09-10
最短 ack 內容 獲得 getchar() 比較 char s str reg
題目描述
毒瘤數據要求判負環
分析:
還是融合了不少題解的思想的。
負環定義:
權值和為負的環
//在網絡上並沒有找到一個官方定義,暫且這麽理解。
SPFA:
支持負邊權的情況.
spfa是最短路算法.如果一個環上的邊權有負的,我們可以重復走這條路來獲得更小的邊權,所以這可以作為我們使用spfa判斷負環的根據
//如果一個位置入隊次數不小於n次,那它一定位於環上,所以這可以作為我們的判斷標準。
聽說STL的隊列比較慢,換掉!
但是如果手打隊列的話
隊尾指針隊首指針一直++根本停不下來怎麽辦?
我們可以重復使用!
像這樣↓
//這三行代碼只是演示,並不是程序中這樣寫。 if(l>n)l=0; if(r>n)r=0; if(l<0)l=n; //因為r一直增加或者重置為0,所以沒必要判斷r<0
考慮把dis值大的放在最下邊,dis值小的放在最上邊。
因為我們取出的位置一直是向前的,所以把dis值小的放在最下邊
(也不能說是最下邊,即放在剛剛取過的位置處,再比較一下與原位置dis值大小.)
至於為什麽盡量去取dis值小的?
因為這些被更新過的點dis值小,我們可能是通過一條負邊到達的此節點,我們再去對它更新一下,可以盡可能早的判斷出負環.
//偷懶的話應該可以用優先隊列來做,不過沒有嘗試,留給您了!
坑:
YE5是5!!! N0是0!!!
----------------AC代碼-----------------
// 3106ms // Creator: 顧z // Date:2018.08.29 //------------------------------------------------ #include<bits/stdc++.h> #define IL inline #define RI register int #define N 100086 #define clear(a) memset(a,0,sizeof a) #define rk for(RI i=1;i<=n;i++) IL void read(int &x){ int f=1;x=0;char s=getchar(); while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();} while(s<='9'&&s>='0'){x=x*10+s-'0';s=getchar();} x*=f; } int n,m,T,s; struct code{int u,v,w;}edge[N<<1]; bool vis[N]; int head[N],tot,dis[N],cnt[N],q[N]; IL void add(int x,int y,int z){edge[++tot].u=head[x];edge[tot].v=y;edge[tot].w=z;head[x]=tot;} IL bool spfa(int s) { int l,r; l=r=0; memset(dis,0x3f,sizeof dis); clear(vis);clear(cnt);clear(q); vis[s]=true;cnt[s]=1;dis[s]=0; q[r++]=s; while(l!=r) { int u=q[l++]; if(l>n)l=0;//重復使用 vis[u]=false; for(RI i=head[u];i;i=edge[i].u) { if(dis[edge[i].v]>dis[u]+edge[i].w) { dis[edge[i].v]=dis[u]+edge[i].w; cnt[edge[i].v]=cnt[u]+1;//題解思想. if(cnt[edge[i].v]>=n and edge[i].w<0) return true; //這裏需要判斷一下邊權是否為負。 //因為看到討論區的一組hack數據,所以嘗試改一下, //然後就過啦~~~ if(!vis[edge[i].v]) { vis[edge[i].v]=true; if(dis[edge[i].v]>dis[q[l]]) { l--; if(l<0) l=n;//重復使用 q[l]=edge[i].v; } else { q[r++]=edge[i].v; if(r>n) r=0;//重復使用 } } } } } return false; } int main() { read(T); while(T--) { s=1,tot=0;clear(head); read(n),read(m); for(RI i=1,u,v,w;i<=m;i++) { read(u),read(v),read(w); add(u,v,w); if(w>=0)add(v,u,w); } puts(spfa(s)?"YE5":"N0"); } }
寫在後面
//這份代碼並沒有考慮多個連通圖中的負環情況
//因此依舊可以被hack掉.
//可能 正確性 or 內容是錯誤的
//提供參考啦~~
p3385 【模板】負環(spfa)