矩阵的幂

Posted jaszzz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了矩阵的幂相关的知识,希望对你有一定的参考价值。

小结

解决的问题:

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

而对于矩阵的幂运算可以用快速幂,复杂度: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;
}

  

 

以上是关于矩阵的幂的主要内容,如果未能解决你的问题,请参考以下文章

幂矩阵和初等矩阵函数

如何计算一个矩阵的幂

幂等矩阵的幂等矩阵性质

如何将矩阵提升到具有多个线程的幂?

矩阵的幂

矩阵的幂