正環,noi.ac模擬賽,floyd倍增
阿新 • • 發佈:2018-11-02
正題
題意很顯然,求一個最小正環。
如果表示i到j走k步需要多久,那麼我們要找出最小的一個k使得有一個不為0.
很明顯可以floyd,每次乘一個走一步的矩陣,那麼乘到有正環就是答案。
時間複雜度
很高興。
那麼明顯我們不會那麼傻,倍增就好了嘛,我們依次處理出走1,2,4,8步的答案,然後將它們類同倍增一樣乘起來,就是答案,有點像lca。
注意,陣列初始化一開始覺得很蒙,應該是
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n,m; struct node{ int g[310][310]; friend node operator*(const node x,const node y){ node q; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) q.g[i][j]=i==j?0:-1e9; for(int k=1;k<=n;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) q.g[i][j]=max(q.g[i][j],x.g[i][k]+y.g[k][j]); return q; } bool pos()const{ for(int i=1;i<=n;i++) if(g[i][i]>0) return true; return false; } }f[10]; int main(){ scanf("%d %d",&n,&m); int x,y,a,b; int now=-1; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) f[0].g[i][j]=i==j?0:-1e9; for(int i=1;i<=m;i++){ scanf("%d %d %d %d",&x,&y,&a,&b); f[0].g[x][y]=a; f[0].g[y][x]=b; } for(int i=1;i<=9;i++){ f[i]=f[i-1]*f[i-1]; if(f[i].pos()) { now=i; break; } } if(now==-1){ printf("0"); return 0; } int ans=0; node q; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) q.g[i][j]=i==j?0:-1e9; for(int i=now-1;i>=0;i--){ if((q*f[i]).pos()) continue; q=q*f[i]; ans+=(1<<i); } printf("%d\n",ans+1); }