zoukankan      html  css  js  c++  java
  • 矩阵的幂

    小结

    解决的问题:

    解决递推关系中不好直接写出通项公式的问题,将多个递推关系的系数在矩阵中表示

    而对于矩阵的幂运算可以用快速幂,复杂度:O(m^3*logn)

    所以算法核心就是找到递推关系对应的矩阵辣

    POJ 3420 Quad Tiling

    题意:在一个4*n的棋盘上,用1*2的多米诺骨牌来平铺,问铺满的方法有多少种。

    思路:这道题不能直接找到明显的递推关系,参考了网上一种  “ 不可分割 ”  拼凑法的概念,这样就可以建立起递推的关系 // 真是妙呀

    当n为奇数且n>=3时,不可分割的平铺方法为2;当n为偶数且n>=4时,不可分割的平铺方法为3;
    所以得到下列递推式:
    f(n)=f(n-1)+f(n-2)*4+f(n-3)*2+f(n-4)*3+…+f(0)*b(n)
    f(n)=f(n-1)+5*f(n-2)+f(n-3)-f(n-4)
    
    f[n-3]    0  1 0 0       f[n-4]

    f[n-2] = 0  0 1 0   *  f[n-3]

    f[n-1]    0  0 0 1      f[n-2]
    f[n]      -1  1 5 1     f[n-1]

    再借用矩阵的模板就ac了

    #include<iostream>
    #include<string.h>
    using namespace std;
    const int MAXN=10;
    const int MAXM=10;
    int r,mod;
    //矩阵类模板
    struct Matrix{
        int n,m;
        int a[MAXN][MAXM];
        void clear(){
            n=m=0;
            memset(a,0,sizeof(a));
        }
        Matrix operator +(const Matrix &b) const {
            Matrix tmp;
            tmp.n=n;tmp.m=m;
            for (int i=0;i<n;++i)
                for(int j=0;j<m;++j)
                    tmp.a[i][j]=a[i][j]+b.a[i][j];
            return tmp;
        }
        Matrix operator -(const Matrix &b)const{
            Matrix tmp;
            tmp.n=n;tmp.m=m;
            for (int i=0;i<n;++i)
                for(int j=0;j<m;++j)
                    tmp.a[i][j]=a[i][j]-b.a[i][j];
            return tmp;
        }
        Matrix operator * (const Matrix &b) const{
            Matrix tmp;
            tmp.clear();
            tmp.n=n;tmp.m=b.m;
            for (int i=0;i<n;++i)
                for(int j=0;j<b.m;++j)
                    for (int k=0;k<m;++k){
                        tmp.a[i][j]+=a[i][k]*b.a[k][j];
                        tmp.a[i][j]%=mod;
                    }
            return tmp;
        }
        Matrix get(int x){//幂运算
            Matrix E;
            E.clear();
            E.n=E.m=n;
            for(int i=0;i<n;++i)
                E.a[i][i]=1;
            if(x==0) return E;
            else if(x==1) return *this;
            Matrix tmp=get(x/2);
            tmp=tmp*tmp;
            if(x%2) tmp=tmp*(*this);
            return tmp;
        }
    };
     
    int main(){
     
        while(cin>>r>>mod){
            if(r==0) break;
            int a[]= {1,1,5,11};
            if(r<=3)
            {
                cout<<a[r]%mod<<endl;
                continue;
            }
            Matrix A;
            A.clear();
            A.n=A.m=4;
            A.a[0][1]=A.a[1][2]=A.a[2][3]=1;
            A.a[3][0]=-1;
            A.a[3][1]=1;
            A.a[3][2]=5;
            A.a[3][3]=1;
            A=A.get(r-3);
            Matrix M;
            M.clear();
            M.n=4;M.m=1;
            M.a[0][0]=M.a[1][0]=1;
            M.a[2][0]=5;
            M.a[3][0]=11;
            M=A*M;
            cout<<(M.a[3][0]+mod)%mod<<endl;
        }
        return 0;
    }
    

      

    POJ 3735 Training little cats

    题意:给了n,m,k分别代表有几只猫,同样的一套动作要做m次,这套动作有k个

    有n只猫,给每只猫放食物:
    g i 代表给第i只猫加一块食物
    e i 代表第i只猫吃完自己的所有食物
    s i j 代表第i只猫,与第j只猫的食物互换

    问这一套动作,做m次,每个猫有多少食物

    思路:显然是矩阵模板题,但是有一点就是这是一个稀疏矩阵,不能直接套用模板

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define ll long long
    #define maxn 105
    int n, m, k;
    struct Mat {
        ll val[maxn][maxn];
        void zero() {
            memset(val, 0, sizeof(val));
        }
        void unit() {
            zero();
            for(int i = 0; i < maxn; i++) val[i][i] = 1;
        }
    }A, T;
    
    Mat operator *(const Mat &a, const Mat &b) {
        Mat tmp;
        tmp.zero();
        for(int k = 0; k <= n; k++) {
            for(int i = 0; i <= n; i++) {
                if(a.val[i][k])
                    for(int j = 0; j <= n; j++)
                        tmp.val[i][j] += a.val[i][k] * b.val[k][j];
            }
        }
        return tmp;
    }
    
    Mat operator ^(Mat x, int n) {
        Mat tmp;
        tmp.unit();
        while(n) {
            if(n & 1) tmp = tmp * x;
            x = x * x;
            n >>= 1;
        }
        return tmp;
    }
    
    void init() {
        A.zero();
        A.val[0][0] = 1;
        T.unit();
    }
    
    int main() {
        char s[5];
        int a, b;
        while(~scanf("%d%d%d", &n, &m, &k)) {
            if(!n && !m && !k) break;
            init();
            for(int i = 0; i < k; i++) {
                scanf("%s", s);
                if(s[0] == 'g') {
                    scanf("%d", &a);
                    T.val[0][a]++;
                } else if(s[0] == 'e') {
                    scanf("%d", &a);
                    for(int i = 0; i <= n; i++) T.val[i][a] = 0;
                } else {
                    scanf("%d%d", &a, &b);
                    for(int i = 0; i <= n; i++) swap(T.val[i][a], T.val[i][b]);
                }
            }
            Mat ans = A * (T ^ m);
            for(int i = 1; i <= n; i++) printf("%lld ", ans.val[0][i]);
            printf("
    ");
        }
        return 0;
    }
    

      

  • 相关阅读:
    Java-技术专区-JVM调优常用参数
    Alibaba-技术专区-Dubbo的SPI应用与原理
    Java-技术专区-深入理解SPI机制
    Alibaba-技术专区-Dubbo SPI扩展点加载机制
    Java-技术专区-线程基础
    Java-技术专区-精巧好用的DelayQueue
    Alibaba-技术专区-Sentinel流量降级监控
    Java-技术专区-Java线程池ThreadPoolExecutor的理解
    SpringCloud-技术专区-SpringCloud组件原理
    机器码和伪指令
  • 原文地址:https://www.cnblogs.com/jaszzz/p/12995197.html
Copyright © 2011-2022 走看看