• zoj3497:Mistwald(矩阵快速幂)


    传送门

    题意

    有一个n*m的矩阵,矩阵上每一个格子有四个传送门,分别通向四个格子,题目给出了每个格子的四个传送门所能到达的地方。起点在(1,1),终点是(n,m),当走到终点的时候就不能再走了,也就是说一旦你到达了终点,就会直接离开这个矩阵。问说从起点开始走P(0 ≤ P ≤ 100,000,000)步能不能到达终点。
    输出的情况是True,Maybe和False。Ture对应的就是走了P步以后只能到达一个点,就是终点。Maybe对应的是走了P步之后还可以到达除了终点以外的其他点。False对应的是P步以后无法到达终点。

    分析

    (显然的矩阵乘法?),不太能理解(菜),看了这篇blog,照着思路敲了敲,2a

    图的临接矩阵A的 p次方Ap中为1的元素(i,j)表示节点i到节点j有一条长度为p的路径(经历的节点可能重复)。要理解矩阵的含义,两个矩阵相乘如果(x,y)元素为1,而(y,z)元素为1,则结果(x,z)元素为1,这表明通过y把x和z连起来了。而题目要求经过终点就不能走了,所以在做矩阵乘法时,需要把(x,n-1) (n-1,y)这样决定的(x,y)去掉。(n-1表示终点)。做乘法时,中间点小心一点就好了。矩阵乘法和floyd在本质上是一样的……
    矩阵的P次方运用的是经典的log(P)的算法。最后看一下结果矩阵的首行(1行)里面有几个1,以及(1,n*m)是不是1,来决定结果。

    trick

    1.开longlong
    2.读入加两个getchar()
    3.不处理(n,m)的传送门

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    int t,n,m,x1,y1,x2,y2,x3,y3,x4,y4,q,p;
    struct matrix
    {
        ll a[50][50];
    }ans,ret;
    matrix multi(matrix x,matrix y)
    {
        int num=n*m;
        matrix tmp;
        for(int i=1;i<=num;++i)for(int j=1;j<=num;++j)
        {
            tmp.a[i][j]=0;
            for(int k=1;k<=num;++k) tmp.a[i][j]+=x.a[i][k]*y.a[k][j];
        }
        return tmp;
    }
    void quick_mod(int p)
    {
        matrix r=ret;
        int num=n*m;
        for(int i=1;i<=num;++i)for(int j=1;j<=num;++j) ans.a[i][j]=(i==j)?1:0;
        for(;p;p>>=1,r=multi(r,r)) if(p&1) ans=multi(ans,r);
    }
    int main()
    {
        for(scanf("%d",&t);t--;)
        {
            scanf("%d %d",&n,&m);getchar();
            memset(ret.a,0,sizeof(ret.a));
            for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)
            {
                scanf("((%d,%d),(%d,%d),(%d,%d),(%d,%d))",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
                getchar();
                if(i==n&&j==m) continue;
                ret.a[(i-1)*m+j][(x1-1)*m+y1]=1;
                ret.a[(i-1)*m+j][(x2-1)*m+y2]=1;
                ret.a[(i-1)*m+j][(x3-1)*m+y3]=1;
                ret.a[(i-1)*m+j][(x4-1)*m+y4]=1;
            }
            //for(int i=1;i<=n*m;++i)for(int j=1;j<=n*m;++j) printf("%d%c",ret.a[i][j],(j==n*m)?'
    ':' ');
            scanf("%d",&q);
    
            while(q--)
            {
                scanf("%d",&p);
                quick_mod(p);
                if(ans.a[1][n*m]==0) { puts("False");continue; }
                bool flag=0;
                for(int i=1;i<n*m;++i) if(ans.a[1][i]) { flag=1;break; }
                if(!flag) puts("True");else puts("Maybe");
            }
            puts("");
        }
    }
    
  • 相关阅读:
    按输入行数,输出对应的倒等腰三角形星星
    按输入行、列数,输出对应的矩形星星
    运算程序,计算玩判断,Y继续,重复计算,N结束
    输入年 月 日 ,计算时该年的第几天
    for计算100以内的奇数和
    创建一个Android项目
    菜鸟大充电啦啦啦啦啦:百度上的安卓学习资料以及我的视频学习资料
    菜鸟大充电啦啦啦啦啦:eclipse SDK 是什么啊
    学习过程的记录:实验室电脑上的jdk环境变量
    WHAT is CPU负载?
  • 原文地址:https://www.cnblogs.com/chendl111/p/6698242.html
Copyright © 2020-2023  润新知