bzoj 2165 DP

  首先如果不考虑数据范围的话,因为每一层都是等效的,所以我们可以用w[i][j][k]来表示在某一层的j位置,称作i次电梯到k位置,最多上升多少层,那么我们可以比较容易的写出转移,因为m十分大,i可能与m同阶,所以我们不能直接枚举i,这样我们考虑二进制的思想,w[2^p][j][k]表示用了2^p次电梯,最多上升的层数,那么这样我们可以直接由w[2^p-1][j][mid]和w[2^p-1][mid][k]转移过来,但是这样求出来的是我们最少用2^p次可以到达m层,最后的答案可能会比这个小,那么我们可以逐位的判断答案,是否可以通过减少某一位的1仍能达到m层,那样我们这个1就可以去掉,也就是不断地更新答案,这样就好了。

  反思:因为最后的答案可能是2^p,但是这样逐位的判断不能讲答案加回2^p,所以需要将答案的初值设为1.

/**************************************************************

    Problem: 2165

    User: BLADEVIL

    Language: C++

    Result: Accepted

    Time:20640 ms

    Memory:11392 kb

****************************************************************/

 

//By BLADEVIL

#include <cstdio>

#include <cstring>

#include <algorithm>

#define maxn 110

#define maxx 60

#define LL long long

 

using namespace std;

 

LL g[maxn][maxn][maxn],p[maxn][maxn],q[maxn][maxn];

LL n,m;

 

void solve() {

    LL t,ans=1;

    scanf("%d%lld",&n,&m);

    memset(g,0,sizeof(g));

    for (int i=1;i<=n;i++)

        for (int j=1;j<=n;j++) {

            t=0;

            scanf("%lld",&g[0][i][j]),g[0][i][j]=min(g[0][i][j],m);

            if (i==1) t=max(t,g[0][i][j]);

        }

    if (t==m) {

        printf("1\n");

        return;

    }

    int k;

    for (k=1;k<=maxx;k++) {

        t=0;

        for (int i=1;i<=n;i++)

            for (int j=1;j<=n;j++) {

                for (int mid=1;mid<=n;mid++)

                    if (g[k-1][i][mid]&&g[k-1][mid][j])

                        g[k][i][j]=max(g[k][i][j],g[k-1][i][mid]+g[k-1][mid][j]);

                g[k][i][j]=min(g[k][i][j],m);

                if (i==1) t=max(t,g[k][i][j]);

            }

        if (t==m) break;

    }

    memcpy(p,g[--k],sizeof(p));

    for (ans+=1LL<<k--;k>=0;k--) {

        memset(q,0,sizeof(q));

        t=0;

        for (int i=1;i<=n;i++)

            for (int j=1;j<=n;j++) {

                for (int mid=1;mid<=n;mid++)

                    if (p[i][mid]&&g[k][mid][j])

                        q[i][j]=max(q[i][j],p[i][mid]+g[k][mid][j]);

                q[i][j]=min(q[i][j],m);

                if (i==1) t=max(t,q[i][j]);

            }

        if (t!=m) {

            ans+=1LL<<k;

            memcpy(p,q,sizeof(p));

        }

    }

    printf("%lld\n",ans);

}

 

int main() {

    int test;

    scanf("%d",&test);

    while (test--) solve();

    return 0;

}

 

你可能感兴趣的:(ZOJ)