• BZOJ 2165: 大楼


    Time Limit: 40 Sec Memory Limit: 259 MB
    Submit: 957 Solved: 353
    [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层或更高的楼层。

    解题思路

    倍增floyd,设dp[i][j][t]是从第i个房间到第j个房间坐了2^t次电梯的最大上升高度,
    dp[i][j][t]=max(dp[i][k][t-1],dp[k][j][t-1])
    然后我们用二进制拆分确定答案。
    注意赋值inf时如果要用<<,一定要用1ll!!!.

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define LL long long
    
    using namespace std;
    const int MAXN = 105;
    const LL inf = 1ll<<60;
    
    inline LL rd(){
        LL x=0,f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
        return x*f;
    }
    
    int T;
    int n;
    LL m,ans=1,cnt;
    
    struct Mat{
        LL mat[MAXN][MAXN];
        Mat (){
            memset(mat,0,sizeof(mat));
        }
        Mat operator*(const Mat &h){
            Mat c;
    //      for(register int i=1;i<=n;i++)
    //          for(register int j=1;j<=n;j++)
    //              c.mat[i][j]=-inf;
            for(register int i=1;i<=n;i++)
                for(register int j=1;j<=n;j++){
                    c.mat[i][j]=-inf;
                    for(register int k=1;k<=n;k++)
                        c.mat[i][j]=max(c.mat[i][j],mat[i][k]+h.mat[k][j]);
    //              if(c.mat[i][j]>m) c.mat[i][j]=m;
                }
            return c;   
        }
    }A,f[MAXN];
    
    inline bool check(Mat x){
        for(register int i=1;i<=n;i++)
            if(x.mat[1][i]>=m) return true;
        return false;
    }
    
    int main(){
        T=rd();
        while(T--){
            ans=1;
            n=rd();m=rd();
            for(register int i=1;i<=n;i++)
                for(register int j=1;j<=n;j++){
                    LL w=rd();
                    if(w==0) f[1].mat[i][j]=-inf;
                    else f[1].mat[i][j]=w;
                }
    //      for(register int i=1;i<=n;i++){
    //          for(register int j=1;j<=n;j++)
    //              cout<<f[1].mat[i][j]<<" ";
    //          cout<<endl;
    //      }
            for(cnt=1;;cnt++){
                f[cnt+1]=f[cnt]*f[cnt];
                if(check(f[cnt+1])) break;
            }
    //      cout<<cnt<<endl;
            A=f[1];
            for(register int i=cnt;i;i--){
                Mat B=A*f[i];
                if(!check(B)){
                    A=B;
                    ans+=(1ll<<i-1);
                }
            }
            printf("%lld
    ",ans+1);
        }
        return 0;
    }
  • 相关阅读:
    搜刮一些开源项目的APP
    iOS Crash文件的解析
    iOS中RGB颜色转换
    随笔杂记
    iOS字体
    方法总结
    经验点滴
    个人理解
    OC 知识点回顾
    IOS UI 笔记整理回顾
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/9676995.html
Copyright © 2020-2023  润新知