2165: 大楼
Time Limit: 40 Sec
Memory Limit: 259 MB
Submit: 837
Solved: 304
[
Submit][
Status][
Discuss]
Description
xz是一个旅游爱好者,这次他来到了一座新的城市。城市中央有一幢高耸入云的大楼。这幢楼到底有多少层呢?据说和非负整数的个数是一样多的。xz想爬上这座大楼来观赏新城市的全景。这幢大楼的楼层从下至上用从小到大的非负整数编号。每层楼有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)。同一行各个数之间均用一个空格隔开。
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
【样例说明】
第一组数据中,使用电梯的顺序为1→2→3→1→2→3→1→4→6→6;第二组数据中,使用电梯的顺序为1→2→3→1→2→3→1→4→5→4→6。第二组数据最后到达了153层,但是没有更短的路径使得恰好到达152层,因此答案为10。
HINT
有如下几类具有特点的数据: 1、有10%的数据所有的n=2; 2、有20%的数据m≤3000; 3、有20%的数据对于满足1≤i,j≤n的整数i和j,若wi,j≠0,则有wi,j≥1015; 4、有30%的数据所有的n=40。以上各类数据均不包含其他类数据。对于所有数据T=5,1≤n≤100,1≤m≤1018;对于满足1≤i,j≤n的整数i和j,有0≤wi,j≤1018。数据保证能够到达m层或更高的楼层。
Source
[ Submit][
Status][
Discuss]
HOME Back
【分析】
翻译一下题目:给一个n个点的有向图,若干条边,每条边u->v,收益为w,询问最少走多少条边才能做到收益和>=m
矩阵乘法乱搞,就是乱搞,我也搞不懂。
其实就是运用了倍增的奇葩思想,还用到了任何一个数都能用2的不同次方的和来表示的奇葩结论。
【代码】
//bzoj 2165 大楼
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 1e18
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(int i=j;i<=k;i++)
using namespace std;
int n,T,tot;
ll m,ans;
struct matrix
{
ll a[105][105];
matrix operator * (const matrix &x) const
{
matrix res;
fo(i,1,n)
fo(j,1,n)
{
res.a[i][j]=-inf;
fo(k,1,n)
res.a[i][j]=max(res.a[i][j],a[i][k]+x.a[k][j]);
res.a[i][j]=min(res.a[i][j],m);
}
return res;
}
}f[101];
inline bool judge(matrix res)
{
fo(i,1,n) if(res.a[1][i]>=m) return 1;
return 0;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%lld",&n,&m);
fo(i,1,n) fo(j,1,n)
{
scanf("%lld",&f[0].a[i][j]);
if(!f[0].a[i][j]) f[0].a[i][j]=-inf;
}
for(tot=1;;tot++)
{
f[tot]=f[tot-1]*f[tot-1];
if(judge(f[tot])) break;
}
ans=1;matrix k=f[0];
for(int i=tot-1;i>=0;i--)
{
matrix x=k*f[i];
if(!judge(x))
k=x,ans+=(1ll<<i);
}
printf("%lld\n",ans+1);
}
return 0;
}