[倍增][Floyd] Bzoj 2165 大楼
题解
- 又学会了一个新姿势——用倍增跑最短路
- 设f[k][i][j]为走了2^k步从房间i走到房间j最多能走多少层
- 转移挺显然的,枚举一个中间层数和步数,转移就好了
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 #define ll long long 7 using namespace std; 8 const ll N=210,inf=1e18; 9 ll T,n,pos,m,ans,f[70][N][N],rec[N],tmp[N]; 10 int main() 11 { 12 freopen("data.in","r",stdin); 13 for (scanf("%lld",&T);T;T--) 14 { 15 scanf("%lld%lld",&n,&m),ans=pos=0; 16 for (ll i=1;i<=n;i++) for (ll j=1;j<=n;j++) scanf("%lld",&f[0][i][j]),f[0][i][j]=(!f[0][i][j])?-inf:f[0][i][j]; 17 for (ll k=1;k<=60;k++) 18 { 19 for (ll i=1;i<=n;i++) 20 for (ll j=1;j<=n;j++) 21 { 22 f[k][i][j]=-inf; 23 for (ll l=1;l<=n;l++) f[k][i][j]=max(f[k][i][j],f[k-1][i][l]+f[k-1][l][j]); 24 } 25 bool flag=false; 26 for (ll i=1;i<=n;i++) if (f[k][1][i]>=m) { flag=true; break; } 27 if (flag) { pos=k; break; } 28 } 29 for (ll i=1;i<=n;i++) rec[i]=f[pos-1][1][i]; 30 ans+=(ll)(1ll<<(pos-1)); 31 for (ll k=pos-2;k>=0;k--) 32 { 33 for (ll i=1;i<=n;i++) 34 { 35 tmp[i]=-inf; 36 for (ll j=1;j<=n;j++) tmp[i]=max(tmp[i],rec[j]+f[k][j][i]); 37 } 38 bool flag=true; 39 for (ll i=1;i<=n;i++) if (tmp[i]>=m) flag=false; 40 if (flag) memcpy(rec,tmp,sizeof(rec)),ans+=(ll)(1ll<<k); 41 } 42 printf("%lld\n",ans+1); 43 } 44 }