题解
- 又学会了一个新姿势——用倍增跑最短路
- 设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
",ans+1);
43 }
44 }