bzoj4773 负环
Description
在忘記考慮負環之后,黎瑟的算法又出錯了。對于邊帶權的有向圖 G = (V, E),請找出一個點數最小的環,使得
環上的邊權和為負數。保證圖中不包含重邊和自環。
Input
第1兩個整數n, m,表示圖的點數和邊數。
接下來的m行,每<=三個整數ui, vi, wi,表<=有一條從ui到vi,權值為wi的有向邊。
2 <= n <= 300
0 <= m <= n(n <= 1)
1 <= ui, vi <= n
|wi| <= 10^4
Output
僅一行一個整數,表示點數最小的環上的點數,若圖中不存在負環輸出0。
Sample Input
3 6
1 2 -2
2 1 1
2 3 -10
3 2 10
3 1 -10
1 3 10
Sample Output
2
分析:
求負環:
A:bellmax ford
B:floyed
C:spfa(扔下去。。。)
設計狀態
f[k][i][j]表示i到j經過k個點的最短路
枚舉k和i,
如果存在f[k][i][i]是負數, 那么就是一個負環
k可以通過倍增得到:f[k]<—f[k-1],f[k-1]
這只是基本原理
具體實現有一些細節
其實我們需要進行兩次floyed
第一次利用倍增的方法
維護好f[k][i][j]
f[k][i][j]=min(f[k-1][i][l]+f[k-1][l][j]);
但是這樣的話我們只知道走2^k步時的答案
想想第一次接觸倍增是什么時候
沒錯,LCA
那時候我們是怎么處理的呢
for (i=lg;i>=0;i–)
這就相當于把答案二進制分解了
得出的答案+1就是最終答案
這道題也是一樣
我們要求的是不存在負環的最大步數,
最大步數+1即為答案
第一次floyed我們得到了一個k(走2^k出現負環)
那答案一定<=2^k
我們就把k從大到小循環
只要是f[k][i][i]>0
ans+=(1 << k)
當然還有一些細節要處理
還記得我們一開始記錄了一個h鄰接矩陣
在循環的開始
我們先調用一個全新的函數:memecpy(a,b,sizeof(b))
表示b中的信息全部復制到a
這個while循環我們可以一步一步看
首先memcpy,g保存一下h數組的信息
設g記錄了走x步時的floyed的答案
之后就進行了一次耳熟能詳的floyed
用來判斷在走2^k+x步數的情況下
能不能走出負環,
能:把h數組的信息還原(這個2^k+x太大了,不符合我們找最大非負環的限制)
不能:ans+=(1 << k),h數組中的信息保留(走2^k+x)
這個h/g數組就相當于記錄沒有負環的最大步數
ans記錄走了多少步
最后輸出ans+1
tip
變量名不要搞錯了
這里寫代碼片 #include<cstdio> #include<iostream> #include<cstring>using namespace std;const int N=310; const int lg=10; int n,m,f[lg][N][N],g[N][N],h[N][N],ans;void floyed() {int i,j,k,l;for (k=1;k<lg;k++){bool ff=0;for (l=1;l<=n;l++) //最外層循環折點 for (i=1;i<=n;i++)for (j=1;j<=n;j++){f[k][i][j]=min(f[k][i][j],f[k-1][i][l]+f[k-1][l][j]);}for (i=1;i<=n;i++)if (f[k][i][i]<0) ff=1;if (ff) break;if ((1<<k)>=n) //整張圖都不存在負環 {puts("0");return;}}ans=0;while (k>=0) //步數{memcpy(g,h,sizeof(h));bool ff=0;for (l=1;l<=n;l++)for (i=1;i<=n;i++)for (j=1;j<=n;j++)h[i][j]=min(h[i][j],g[i][l]+f[k][l][j]);for (i=1;i<=n;i++)if (h[i][i]<0) ff=1;if (ff) memcpy(h,g,sizeof(g)); //恢復信息 else ans+=(1<<k);k--;} printf("%d",ans+1); }int main() {scanf("%d%d",&n,&m);memset(f,0x33,sizeof(f));memset(h,0x33,sizeof(h));for (int i=1;i<=n;i++) f[0][i][i]=h[i][i]=0; //h鄰接矩陣 for (int i=1;i<=m;i++) {int u,w,z;scanf("%d%d%d",&u,&w,&z);f[0][u][w]=z;}floyed();return 0; }轉載于:https://www.cnblogs.com/wutongtong3117/p/7673380.html
總結
以上是生活随笔為你收集整理的bzoj4773 负环的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: AAPT2 error: check l
- 下一篇: Cadence 17.4 等长布线