zoukankan      html  css  js  c++  java
  • PKU 3318 Matrix Multiplication(随机化算法||状态压缩)

    题目大意:原题链接

    给定三个n*n的矩阵A,B,C,验证A*B=C是否成立.

    所有解法中因为只测试一组数据,因此没有使用memset清零

    Hint中给的傻乎乎的TLE版本:

    #include<cstdio>
    #include<cstring>
    int n,A[510][510];
    int B[510][510],C[510][510];
    void Input(int m[510][510])
    {
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                scanf("%d",&m[i][j]);
        }
    }
    int main()
    {
        scanf("%d",&n);
        bool sign=true;
        Input(A),Input(B),Input(C);
        for(int i=1;i<=n&&sign;i++){
            for(int j=1;j<=n&&sign;j++){
                int sum=0;
                for(int k=1;k<=n&&sign;k++)
                    sum+=A[i][k]*B[k][j];
                if(sum!=C[i][j]) sign=false;
            }
        }
        if(sign) printf("YES");
        else printf("NO");
    }

    AC版本解法一:神奇的输入优化

    之前就看到过几次一个神奇的输入模板,不知道这段代码是否就是那个(提交多次,觉得估计在提交人数多时容易超时)

    #include<cstdio>
    using namespace std;
    int n,A[505][505];
    int B[505][505],C[505][505];
    
    int Read()
    {
        int d=0;
        char ch,t=0;
        while((ch=getchar())==' '||ch=='
    ') ;
        if(ch=='-') t=1;
        else d=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')
            d=d*10+ch-'0';
        if(t) return -d;
        else return d;
    }
    
    int main()
    {
        scanf("%d",&n);
        bool sign=true;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                A[i][j]=Read();
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                B[i][j]=Read();
        }
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++)
                C[i][j]=Read();
        }
        for(int i=0;i<n&&sign;i++){
            for(int j=0;j<n&&sign;j++){
                int sum=0;
                for(int k=0;k<n;k++)
                    sum+=A[i][k]*B[k][j];
                if(sum!=C[i][j]){
                    sign=false;
                    break;
                }
            }
        }
        if(sign) printf("YES");
        else printf("NO");
    }

    AC版本解法二:稳稳的随机化算法

    #include<ctime>
    #include<cstdio>
    #include<cstdlib>
    #define TLE 2000
    int n,A[510][510];
    int B[510][510],C[510][510];
    
    void Input(int m[510][510])
    {
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                scanf("%d",&m[i][j]);
        }
    }
    bool Judge()
    {
        int r,c;//随机行数,列数 
        int time=50*TLE;//注意取的次数需要适当 
        while(time--){
            r=rand()%n+1,c=rand()%n+1;
            int sum=0;
            for(int k=1;k<=n;k++)
                sum+=A[r][k]*B[k][c];
            if(sum!=C[r][c]) return 0;
        }
        return 1;
    }
    
    int main()
    {
        scanf("%d",&n);
        srand(time(NULL));
        Input(A),Input(B),Input(C);
        if(Judge()) printf("YES");
        else printf("NO");
    }

    AC版本解法三:流弊的状态压缩

    思路;

    /*

    Problem B: Matrix Multiplication

    The author gives an approximate algorithm rather than a precise one.

    Randomize a n ×1 matrix X, test if the equation A × B × X = C × X holds true.

    If it is not true we can safely say "NO" to this problem.

    If it is true, the possibility that  A × B  X is extremely little.

    */

    上面是北大网站上的提示,用行向量把C矩阵A*B矩阵压缩了,看这一句:

    Randomize a n ×1 matrix X,用一个随机的列向量。

     

    具体怎实现呢?

     

    用压缩矩阵再比较的方法:

     

    我习惯左乘一个行向量,所以设一个行向量XX1*n的矩阵,若A*B等于C则必有X*A*B等于X*C,虽然多乘了一个向量,但是时间复杂度却降低到了O(n^2)了。

     

    这样解的实质是把一个方阵压缩成了一个行向量,向量的每一个元素都是原矩阵该列的的和,也就是说用和来比较。这样大大节省了时间。但是带来一个问题:

     

    如这两个矩阵:

     

           x x x x x x x x x x                    x x x x x x x x x x

     

           x x 1 x x x x 1 x x                    x x 0 x x x x 2 x x

     

           x x x x x x x x x x                    x x x x x x x x x x

     

           x x 1 x x x x 1 x x                    x x 2 x x x x 0 x x

     

           ……                                          ……

     

           x x x x x x x x x x                    x x x x x x x x x x

     

           用压缩再比较的方法不能得到正确结果。压缩再比较的关键在于怎么样在和中体现原来每个元素的个性。关键就是X行向量怎么设定。题目在比赛结束后提示是一个随机的向量X,就是把X的每个元素设为随机数。我觉得可以把X设为一个递增的向量:{12n},这样更能体现每个元素的个性,而随机有可能在关键点上出现错误。

    #include<cstdio>
    int n,A[510][510];
    int B[510][510],C[510][510];
    int E[510],e[510],t[510];
    void Input(int m[510][510])
    {
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++)
                scanf("%d",&m[i][j]);
        }
    }
    bool Judge(int n)
    {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                t[i]+=j*A[j][i];
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                e[i]+=t[j]*B[j][i];
        for(int i=1;i<=n;i++)
            if(e[i]!=E[i]) return false;
        return true;
    }
    int main()
    {
        scanf("%d",&n);
        Input(A),Input(B),Input(C);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                E[i]+=j*C[j][i];//关键部分:j*C[j][i]就是给C矩阵左乘了一个递增的行向量X:{1,2,3,...,n}
        if(Judge(n)) printf("YES");
        else printf("NO");
    }

     

     

  • 相关阅读:
    escape
    洛谷 P2158 【仪仗队】
    GIT学习----第五节:管理修改
    前端Webpack
    20 行 JS 代码,实现复制到剪贴板功能
    mysql表分区和分表的实现方式几种以及区别,什么时候用
    微信小程序----解析px、rpx、rem、vw实现页面布局
    微信小程序----相对路径图片不显示
    微信小程序----评价系统中的评星
    微信小程序----session_key失效导致的后台错误wxsp login api aesCbcUtil error info: pad block corrupted
  • 原文地址:https://www.cnblogs.com/freinds/p/6420806.html
Copyright © 2011-2022 走看看