Description
xz是一个旅游爱好者,这次他来到了一座新的城市。城市中央有一幢高耸入云的大楼。这幢楼到底有多少层呢?据说和非负整数的个数是一样多的。xz想爬上这座大楼来观赏新城市的全景。
这幢大楼的楼层从下至上用从小到大的非负整数编号。每层楼有n个房间,用1到n的正整数编号。楼层之间用电梯连接,电梯只能上行,不能下行或者同层移动。(下楼一般自行解决)电梯用(u,v,w)的形式给出,表示对于任意正整数i,有第i层的房间u到第i+w层的房间v有一部电梯。电梯只能从起点开往终点,不能中途停留。
xz想要观赏城市全景,至少需要登上第m层楼,即最终需要到达的楼层数≥m。由于乘坐电梯要缴纳高额的费用,而如果花销太大回家就没法报账了,xz希望乘坐电梯的次数最少。现在xz在第0层的1号房间,你需要求出这个最少的乘坐次数。
这幢大楼的楼层从下至上用从小到大的非负整数编号。每层楼有n个房间,用1到n的正整数编号。楼层之间用电梯连接,电梯只能上行,不能下行或者同层移动。(下楼一般自行解决)电梯用(u,v,w)的形式给出,表示对于任意正整数i,有第i层的房间u到第i+w层的房间v有一部电梯。电梯只能从起点开往终点,不能中途停留。
xz想要观赏城市全景,至少需要登上第m层楼,即最终需要到达的楼层数≥m。由于乘坐电梯要缴纳高额的费用,而如果花销太大回家就没法报账了,xz希望乘坐电梯的次数最少。现在xz在第0层的1号房间,你需要求出这个最少的乘坐次数。
Input
第一行包含一个正整数T,表示数据的组数。接下来的数据分为T个部分。
每个部分第一行包含两个正整数n和m,意义见题目描述。
接下来n行,每行包含n个非负整数。这n行中,第i行第j个数为wi,j,如果wi,j非零,则表示有电梯(i,j,wi,j)。
同一行各个数之间均用一个空格隔开。
每个部分第一行包含两个正整数n和m,意义见题目描述。
接下来n行,每行包含n个非负整数。这n行中,第i行第j个数为wi,j,如果wi,j非零,则表示有电梯(i,j,wi,j)。
同一行各个数之间均用一个空格隔开。
Output
对于每组数据,输出一行一个正整数,最少的乘坐次数。
Sample Input
2 6 147 0 1 0 50 0 0 0 0 1 0 0 0 20 0 0 0 0 0 0 0 0 0 1 50 0 0 0 8 0 0 0 0 0 0 0 3 6 152 0 1 0 50 0 0 0 0 1 0 0 0 20 0 0 0 0 0 0 0 0 0 1 50 0 0 0 8 0 0 0 0 0 0 0 3
Sample Output
9 10
Data Constraint
Hint
【样例说明】
第一组数据中,使用电梯的顺序为1→2→3→1→2→3→1→4→6→6;第二组数据中,使用电梯的顺序为1→2→3→1→2→3→1→4→5→4→6。第二组数据最后到达了153层,但是没有更短的路径使得恰好到达152层,因此答案为10。
【数据规模及约定】
有如下几类具有特点的数据:
1、有10%的数据所有的n=2;
2、有20%的数据m≤3000;
3、有20%的数据对于满足1≤i,j≤n的整数i和j,若wi,j≠0,则有wi,j≥10^15;
4、有30%的数据所有的n=40。
以上各类数据均不包含其他类数据。
对于所有数据T=5,1≤n≤100,1≤m≤10^18;对于满足1≤i,j≤n的整数i和j,有0≤wi,j≤10^18。
数据保证能够到达m层或更高的楼层。
第一组数据中,使用电梯的顺序为1→2→3→1→2→3→1→4→6→6;第二组数据中,使用电梯的顺序为1→2→3→1→2→3→1→4→5→4→6。第二组数据最后到达了153层,但是没有更短的路径使得恰好到达152层,因此答案为10。
【数据规模及约定】
有如下几类具有特点的数据:
1、有10%的数据所有的n=2;
2、有20%的数据m≤3000;
3、有20%的数据对于满足1≤i,j≤n的整数i和j,若wi,j≠0,则有wi,j≥10^15;
4、有30%的数据所有的n=40。
以上各类数据均不包含其他类数据。
对于所有数据T=5,1≤n≤100,1≤m≤10^18;对于满足1≤i,j≤n的整数i和j,有0≤wi,j≤10^18。
数据保证能够到达m层或更高的楼层。
题解
- 又学会了一个新姿势——用倍增跑最短路
- 设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 }