• zoj3497 Mistwald(矩阵快速幂)


    题意:给定一个有向图(最多25个节点,每个节点的出度最多为4),给定起点和终点,然后从起点开始走,走到终点就停止,否则一直往下走,问能不能P步到达终点。也就是说从起点出发,走一条长度为P的路径,路径中间点不能经过终点(但可以反复经过其他点)。如果从起点出发P步后,不能到达终点,就是False,如果可以到达终点也可以到其他别的点,就是Maybe,如果P步后只能到达终点(到别的点没有长度为P的路径),则是Yes。

    样例输入意思:四个坐标分别为,m*n矩阵中的坐标,通过次计算出每个节点对应的出口,然后建图。

    分析:图的邻接矩阵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在本质上是一样的……

    Orz..矩阵乘法还可以写成松弛操作。(是我辣鸡了)

    矩阵的P次方运用的是经典的log(P)的算法。最后看一下结果矩阵的首行(0行)里面有几个1,以及(0,n-1)是不是1,来决定结果。

    #include<iostream>
    #include<cstdio> 
    #include<cstring>
    #define maxn 30
    using namespace std;
    struct mat{
        int a[maxn][maxn];
    };
    mat map;
    int mul;
    mat mat_mul(mat x,mat y){
        mat ans;
        memset(ans.a,0,sizeof(ans.a));
        for (int i=1;i<=mul;i++)
            for (int j=1;j<=mul;j++)
            for (int k=1;k<=mul;k++){
                ans.a[i][j]+=x.a[i][k]*y.a[k][j];
            }
        return ans;
    }
    mat mat_pow(mat map,int k){ //map的k次方 
        mat c=map,res=map;
        k--;
        while (k){
            if (k&1) res=mat_mul(res,c);
            k>>=1;
            c=mat_mul(c,c);
        }
        return res;
    }
    int main(){
        int t,m,n,q;char ch;
        int xx;
        int x[5],y[5];
        scanf("%d",&t);
        while (t--){
            scanf("%d%d",&m,&n);scanf("%c",&ch);
            mul=m*n;
            memset(map.a,0,sizeof(map.a));
            for (int i=1;i<=m;i++){
                for (int j=1;j<=n;j++){
                    scanf("((%d,%d),(%d,%d),(%d,%d),(%d,%d))",&x[0],&y[0],&x[1],&y[1],&x[2],&y[2],&x[3],&y[3]);
                    scanf("%c",&ch);
                    if (i==m && j==n) continue; //途中路径不能经过终点
                    for (int k=0;k<4;k++){
                        map.a[(i-1)*n+j][(x[k]-1)*n+y[k]]=1;
                    }
                }
            }
            scanf("%d",&q);
            while (q--){
                scanf("%d",&xx);
                mat S;
                if (xx) S=mat_pow(map,xx);
                else {
                    memset(S.a,0,sizeof(S.a));
                    for (int i=0;i<=mul;i++) S.a[i][i]=1;
                }
                if (!S.a[1][mul]) printf("False
    ");
                else {
                    int flag=0;
                    for (int i=1;i<mul;i++){
                        if (S.a[1][i]){
                            flag=1;
                            break;
                        }
                    }
                    if (flag) printf("Maybe
    ");
                    else printf("True
    ");
                }
            }
            printf("
    ");
        }
        return 0;
    }

    PS.迷之TLE无数发。各种迷。最后是因为快速幂姿势和别人有所不同,矩阵的0次方需要特判赋值为单位矩阵。orz....太菜了。

  • 相关阅读:
    C++强大的背后
    C++ 非托管的vc工程中部分文件使用.Net Framwork
    C++ 基于 Visual C++6.0 的 DLL 编程实现
    C++ 中指针,指针的引用,指针的指针的区别
    C# 中重用c/c++旧模块
    C++ 打开exe文件的方法(VS2008)
    C++ 指针 指针高级<高质量编程>
    C++ 函数指针
    有用但不常见的c++函数
    C++ int & *p; //不能建立指向引用的指针;int *a; int * & p=a; //正确,指针变量的引用
  • 原文地址:https://www.cnblogs.com/changer-qyz/p/8442857.html
Copyright © 2020-2023  润新知