1. 程式人生 > >bzoj4773: 負環(倍增floyd)

bzoj4773: 負環(倍增floyd)

cstring pla bzoj -a += for algorithm lose ans

  浴谷夏令營例題...講師講的很清楚,沒看題解代碼就自己敲出來了

  f[l][i][j]表示i到j走2^l條邊的最短距離,顯然有f[l][i][j]=min(f[l][i][j],f[l-1][i][k]+f[l-1][k][j])。

  是否有負環可以用f[l][i][i]是否<0來判,我們從高位往低位貪心,找到走的邊數最大的沒有負環的圖,把最大走的邊數+1就必定有負環,也就是答案了。

技術分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include
<cmath> #include<algorithm> using namespace std; const int maxn=310,inf=1e9; int n,m,x,y,ans; int f[10][maxn][maxn],g[maxn][maxn],h[maxn][maxn]; inline void read(int &k) { int f=1;k=0;char c=getchar(); while(c<0||c>9)c==-&&(f=-1),c=getchar(); while
(c<=9&&c>=0)k=k*10+c-0,c=getchar(); k*=f; } int main() { read(n);read(m);int L=(int)ceil(log(n)/log(2)); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) { for(int k=0;k<=L;k++)f[k][i][j]=(i-j||k)?inf:0; g[i][j]=(i-j)?inf:0; } for(int
i=1;i<=m;i++)read(x),read(y),read(f[0][x][y]); for(int l=1;l<=L;l++) for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[l][i][j]=min(f[l][i][j],f[l-1][i][k]+f[l-1][k][j]); int FLAG=0; for(;L>=0;L--) { for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)h[i][j]=(i-j)?inf:0; int flag=0; for(int k=1;k<=n;k++) { for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) h[i][j]=min(h[i][j],f[L][i][k]+g[k][j]); if(h[i][i]<0){flag=1;FLAG=1;break;} } if(flag)break; } if(flag)continue; for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)g[i][j]=h[i][j]; ans+=1<<L; } printf("%d",FLAG?ans+1:0); }
View Code

bzoj4773: 負環(倍增floyd)