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层或更高的楼层。

/*
f[p][i][j]表示用了p次电梯,从i房间到j房间的最高楼层。
f[p][i][j]=max(f[p/2][i][k],f[p/2][k][j])
然后用矩阵乘法算f[2],f[4],f[8]...
直到某个f第一行出现大于m的数。
然后用二进制拆分求出答案。
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 110
#define lon long long
#define inf 1000000000000000000LL
using namespace std;
int n,cnt;
lon m;
lon read(){
lon num=,flag=;char c=getchar();
while(c<''||c>''){if(c=='-')flag=-;c=getchar();}
while(c>=''&&c<=''){num=num*+c-'';c=getchar();}
return num*flag;
}
struct M{
lon v[N][N];
M(){
memset(v,,sizeof(v));
}
}f[N];
M operator*(M a,M b){
M c;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
c.v[i][j]=-inf;
for(int k=;k<=n;k++)
c.v[i][j]=max(a.v[i][k]+b.v[k][j],c.v[i][j]);
if(c.v[i][j]>m) c.v[i][j]=m;
}
return c;
}
bool check(M x){
for(int i=;i<=n;i++)
if(x.v[][i]>=m) return true;
return false;
}
int main(){
int T;scanf("%d",&T);
while(T--){
n=read();m=read();
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){
f[].v[i][j]=read();
if(!f[].v[i][j]) f[].v[i][j]=-inf;
}
for(cnt=;;cnt++){
f[cnt+]=f[cnt]*f[cnt];
if(check(f[cnt+])) break;
}
M t=f[];lon ans=;
for(int i=cnt;i;i--){
M x=t*f[i];
if(!check(x)){
for(int j=;j<=n;j++)
for(int k=;k<=n;k++)
t.v[j][k]=x.v[j][k];
ans+=1LL<<(i-);
}
}
cout<<ans+<<endl;
}
return ;
}

大楼(bzoj 2165)的更多相关文章

  1. [BZOJ 2165] 大楼 【DP + 倍增 + 二进制】

    题目链接:BZOJ - 2165 题目分析: 这道题我读了题之后就想不出来怎么做,题解也找不到,于是就请教了黄学长,黄学长立刻秒掉了这道题,然后我再看他的题解才写出来..Orz 使用 DP + 倍增 ...

  2. BZOJ 2165: 大楼 倍增Floyd

    卡了一上午常数,本地13s,可是bzoj 就是过不去~ #include <bits/stdc++.h> #define N 102 #define M 55 #define ll lon ...

  3. BZOJ 2165: 大楼

    Time Limit: 40 Sec Memory Limit: 259 MB Submit: 957 Solved: 353 [Submit][Status][Discuss] Descriptio ...

  4. bzoj 2165: 大楼【Floyd+矩阵乘法+倍增+贪心】

    1<<i的结果需要是long long的话i是long long是没用的--要写成1ll<<i--我别是个傻子吧 虽然写的是二进制贪心,但是我觉得二分可能更好写吧(但是会慢) ...

  5. bzoj 2165 DP

    首先如果不考虑数据范围的话,因为每一层都是等效的,所以我们可以用w[i][j][k]来表示在某一层的j位置,称作i次电梯到k位置,最多上升多少层,那么我们可以比较容易的写出转移,因为m十分大,i可能与 ...

  6. 【BZOJ】2165: 大楼

    [题意]从第0层开始有无穷层,每层有n个房间,给定矩阵A,A[i][j]表示从第x层的房间 i 可以跳到第x+A[i][j]层的房间 j (x任意),A[i][j]=0表示不能跳.初始在第0层第1个房 ...

  7. BZOJ刷题指南(转)

    基础(65) 巨水无比(4):1214.3816:2B题:1000A+B:2462:输出10个1 模拟/枚举/暴力(15):4063傻子模拟:1968小学生暴力:1218前缀和暴力:3856读英文:4 ...

  8. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  9. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

随机推荐

  1. nodejs 用户登录密码md5加密

    jade文件 div.login ul.inp-content  li span= '用户名:' input.ui-input1#input1(placeholder='请输入手机号')  li sp ...

  2. 第18题:在O(1)时间删除链表结点+删除链表中重复的节点

    题目描述:题目描述在O(1)时间删除链表结点 给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点. 考查创新编程能力. 思路: 1.如果从头到尾遍历,时间O(n) 2.如果将待删 ...

  3. 1.在Cisco Packet Tracer里交换机的初始配置

    基本拓扑图: 点进交换机,会先进入交换机的用户模式,这个模式下交换机的名称后方会以‘>’显示 输入enable会进入交换机的特权模式,同样在交换机的名称后方以‘#’显示 在特权模式的环境下输入c ...

  4. Java课堂作业详解

    今天的Java课堂留下了一个作业:使用Eclipse编写一个程序,使输入的两个数进行加和,并且输出他们的和.对于这个题目,我们首先可以把它分解成为三个不同的小步骤 第一步就是输入这两个数,因为我们无需 ...

  5. ActiveMQ发布-订阅消息模式(同点对点模式的区别)

    点对点与发布订阅最初是由JMS定义的.这两种模式主要区别或解决的问题就是发送到队列的消息能否重复消费(多订阅) 点对点: 消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费 ...

  6. Codeforces Round #435 (Div. 2) B (二分图) C(构造)

    B. Mahmoud and Ehab and the bipartiteness time limit per test 2 seconds memory limit per test 256 me ...

  7. 二叉树的镜像(Python实现)

    题目 给定一棵二叉树,要求输出其左右翻转后二叉树的中序遍历. 例: 翻转前: 翻转后: 1 | 1 / \ | / \ 2 3 | 3 2 / \ | / \ 4 5 | 5 4 解析 两个步骤: 镜 ...

  8. hive实现根据用户分组,按用户记录求上下两条记录的时间差

    在mysql,数据如下:#查询某一用户该日抽奖时间 select draw_time from user_draw_log where user_id = 1 and draw_date='2016- ...

  9. border,border-width不支持百分比

    1.border-width不支持百分比 原因:不会因为设备大就按比例变大 同样的,outline,box-shadow,text-shadow也不支持百分比 也就是border不支持百分比 2.bo ...

  10. SSH的基本操作

    一. 登陆SSH远程控制服务器 我们以192.168.100.42服务器为例. SSH乱码: LANG="zh_CN.GB18030" export LANG=zh_CN.gb23 ...