• POJ 3735 Training little cats(矩阵乘法)


    【题目链接】 http://poj.org/problem?id=3735

    【题目大意】

      有一排小猫,给出一系列操作,包括给一只猫一颗花生,
      让某只猫吃完所有的花生以及交换两只猫的花生,
      求完成m次操作集合之后每只猫的花生数量

    【题解】

      创建一个1*(n+1)的初始矩阵,
      对于给第i只猫一个花生就相当于乘上修改了A[0][i]的单位矩阵
      如给第一只猫一个花生就修改A[0][1]为1
      得到:
        1 1 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 1
      然后我们用初始矩阵去乘这个矩阵,就完成了加的操作
      对于让第i只猫吃完所有的花生,我们将A[i][i]修改为0
      如让第三只猫吃完花生,那么就相当于将A[3][3]改为0
      得到
        1 0 0 0
        0 1 0 0
        0 0 1 0
        0 0 0 0
      然后我们用初始矩阵去乘这个矩阵,就完成了清零的操作
      对于交换花生的操作,我们交换单位矩阵的第x和y行,然后相乘即可
      比如交换第一只猫和第三只猫的花生,我们就得到
        1 0 0 0
        0 0 0 1
        0 0 1 0
        0 1 0 0
      乘到初始矩阵上即可
      我们发现经过这些操作,我们最后会得到一个操作集合的矩阵表达
      而这些操作的变换其实不用整个乘上矩阵,只要直接修改单位矩阵的部分值即可
      第一种操作的影响可以转化为A[0][x]++
      第二种操作的影响可以转化为A[0~n][x]=0
      第三种操作的影响可以转化为i_0^n swap(A[i][x],A[i][y])
      那么我们直接计算转置矩阵即可。

    【代码】

    #include <cstdio>
    #include <vector>
    #define rep(i,n) for(int i=0;i<n;i++)
    using namespace std;
    typedef long long LL; 
    typedef vector<vector<LL> > mat;
    LL n,m,k,x,y;
    char op[10];
    mat mul(mat &A,mat &B){
        mat C(A.size(),vector<LL>(B[0].size()));
        rep(i,A.size())rep(k,B.size())if(A[i][k]){
            rep(j,B[0].size())C[i][j]+=A[i][k]*B[k][j];
        }return C;
    }
    mat pow(mat A,LL n){
        mat B(A.size(),vector<LL>(A.size()));
        rep(i,A.size())B[i][i]=1;
        for(;n;n>>=1){if(n&1)B=mul(B,A);A=mul(A,A);}
        return B;
    }
    int main(){
        while(scanf("%lld%lld%lld",&n,&m,&k),n+m+k){  
            mat A(n+1,vector<LL>(n+1));
            rep(i,n+1)A[i][i]=1;
            while(k--){
                scanf("%s",&op);
                if(op[0]=='g'){
                    scanf("%lld",&x);
                    A[0][x]++;
                }else if(op[0]=='e'){
                    scanf("%lld",&x);
                    rep(i,n+1)A[i][x]=0;
                }else{
                    scanf("%lld%lld",&x,&y);
                    rep(i,n+1)swap(A[i][x],A[i][y]);
                }
            }if(m){
                A=pow(A,m);
                printf("%lld",A[0][1]);
                for(int i=2;i<=n;i++)printf(" %lld",A[0][i]);
                puts("");
            }else{
                printf("0");
                rep(i,n-1)printf(" 0");
                puts("");
            }
        }return 0;
    }
  • 相关阅读:
    输入n个整数,输出其中最小的k个
    输出单向链表中倒数第k个结点
    扑克牌大小
    Optional<T> 避免和null检查相关的bug
    筛选、切片、匹配、查找、匹配、归约
    java8 流 中的常用函数式接口
    action 和 controller 单例与多例问题
    Collections.sort Comparator.comparing 冒泡排序 效率对比
    java8 流
    将逗号分割的列,变成多列
  • 原文地址:https://www.cnblogs.com/forever97/p/poj3735.html
Copyright © 2020-2023  润新知