北邮机试 | bupt oj | 96. 矩阵幂 | 快速幂以及矩阵快速幂详细解答

目录

题目描述

输入格式

输出格式

输入样例

输出样例

 AC代码

知识点学习:

快速幂

矩阵乘法

矩阵快速幂


矩阵幂

时间限制 1000 ms 内存限制 65536 KB

题目描述

​给你一个n*n的矩阵

求其矩阵的k次幂,即Pk

输入格式

第一行,一个整数T(0<T<=10),表示要求矩阵的个数。

接下来有T组数据,每组数据格式如下:

第一行:两个数据n(2<=n<=10)、k(1<=k<=5),两个数字之间用一个空格隔开,其中n表示状况空间的总数,k表示待求的转移概率矩阵的步数。接下来有n行n列个正整数,其中,第i行第j列表示pij,(0<=pij<=10)。另外,数据保证最后结果不会超过10^8。

输出格式

输出为T组数据。

每组数据为已知矩阵的k次幂,格式为:

n行n列个正整数,每行数之间用空格隔开,注意,每行最后一个数后面不应该有多余的空格。

输入样例

3
2 2
9 8
9 3
3 3
4 8 4
9 3 0
3 5 7
5 2
4 0 3 0 1
0 0 5 8 5
8 9 8 5 3
9 6 1 7 8
7 2 5 7 3

输出样例

153 96
108 81
1216 1248 708
1089 927 504
1161 1151 739
47 29 41 22 16
147 103 73 116 94
162 108 153 168 126
163 67 112 158 122
152 93 93 111 97

 AC代码

 #include<bits/stdc++.h>
using namespace std;
#define For(i,m,n) for(int i=m;i<n;i++)
#define MAXN 12

int Matrix[MAXN][MAXN];
int ans[MAXN][MAXN];
void M_input(int n,int _Matrix[][MAXN]){
    For(i,0,n){
        For(j,0,n){
            scanf("%d",&_Matrix[i][j]);
        }
    }
}
void M_output(int n,int _Matrix[][MAXN]){
    For(i,0,n){
        For(j,0,n){
            printf("%d ",_Matrix[i][j]);
            if(j!=n-1){
                printf(" ");
            }
        }
        printf("\n");
    }
}
void M_multi(int Matrix_A[][MAXN],int Matrix_B[][MAXN],int n){
    int temp[MAXN][MAXN];
    memset(temp,0,sizeof temp);
    For(i,0,n){
        For(j,0,n){
            For(k,0,n){
                temp[i][j] += Matrix_A[i][k]*Matrix_B[k][j];
            }
        }
    }
    For(i,0,n){
        For(j,0,n){
            Matrix_A[i][j] = temp[i][j];
        }
    }
}
//得到单位阵
void makeE(int n,int ans[][MAXN]){
    For(i,0,n){
        For(j,0,n){
            if(i==j){
                ans[i][j] = 1;
            }
            else{
                ans[i][j]=0;
            }
        }
    }
}
void quickPower(int n,int k,int _ans[][MAXN],int _Matrix[][MAXN]){
    //初始化ans
    makeE(n,_ans);
    while(k){
        if(k&1){
            M_multi(_ans,_Matrix,n);
        }
        M_multi(_Matrix,_Matrix,n);
        k>>=1;
    }
}
int main()
{
    int t,n,k;
    scanf("%d",&t);
    while(t--){
        scanf("%d %d",&n,&k);
        M_input(n,Matrix);
        quickPower(n,k,ans,Matrix);
        M_output(n,ans);
    }
    return 0;
}

唐主席代码:

#include <bits/stdc++.h>
#define FF(a,b) for(int a=0;a<b;a++)
#define F(a,b) for(int a=1;a<=b;a++)
#define LEN 100
#define INF 1000000
#define bug(x) cout<<#x<<"="<<x<<endl;

using namespace std;
typedef long long ll;

typedef struct matrix{
    int m[LEN][LEN];
    int row,col;
    matrix(int row,int col):row(row),col(col){}
    matrix(){
    }
    void input(){
        FF(i,row)
            FF(j,col)
                scanf("%d",&this->m[i][j]);
    }
    void output(){
        FF(i,row)
        {
            FF(j,col)
            {
                printf("%d",this->m[i][j]);
                if(j!=col-1) putchar(' ');
            }
            printf("\n");
        }
    }
}matrix;

matrix* multi(matrix& A, matrix& B){
    matrix* C=new matrix;
    C->row=A.row;
    C->col=B.col;
    for(int i=0;i<A.row;i++)
        for(int j=0;j<B.col;j++)
            for(int k=0;k<A.col;k++)
                C->m[i][j]+=A.m[i][k]*B.m[k][j];
    return C;
}


matrix quickPower(matrix& A,int p){    //A^p
    int n=A.col;
    //得到单位阵
    matrix ans(n,n);//ans=E
    FF(i,n)
        FF(j,n)
            if(i==j)
                ans.m[i][j]=1;
            else
                ans.m[i][j]=0;
    //开始快速幂
    matrix base=A;
    while(p){
        if(p&1)
            ans=*multi(ans,base);
        base=*multi(base,base);
        p>>=1;
    }
    return ans;
}

int main()
{
//    freopen("./in","r",stdin);
    int N;
    scanf("%d",&N);
    while(N--){
        int n,p;
        scanf("%d%d",&n,&p);
        matrix A(n,n);
        A.input();
        quickPower(A,p).output();
    }
    return 0;
}

知识点学习:

来自唐主席的博客!我是唐主席死忠粉!

我给大家加了备注!更方便食用。

下面是唐主席的博客。

https://blog.csdn.net/TQCAI666/article/details/86673441

快速幂

//  a^(n)=a^(n/2)*a^(n/2) 来节省乘法运算次数
ll quickPower(ll a,ll b){
    //底为a,指数为b
    ll ans=1,base=a;
    while(b>0){
        //& 按位与运算 如果指数为奇数,需要乘一次底数
        if(b&1){
            ans*=base;
        }
        base*=base;
        // >> 有符号右移 将运算数的二进制整体右移指定位数,整数高位用0补齐,负数高位用1补齐
        // 此处相当于b = b/2
        b>>=1;
    }
    return ans;
}

比如

a^11  11二进制码为1011。此时 b = 1011(B)

第一轮

b&1=true ans = ans * base = a

base *=base   base = a^2

b = 101(B)

第二轮

b&1 = true ans = ans * base = a^3

base = a^4

b = 10(B)

第三轮

b&1 false

base = a^8

b = 1(B)

第四轮

b&1=true ans = ans*base = a^3 * a^8 = a^11

循环到这里就结束了

 

矩阵乘法

matrix* multi(matrix& A, matrix& B){
    //创建一个新的矩阵保存计算后的数据
    matrix* C=new matrix;
    //矩阵乘法的运算规则
    C->row=A.row;
    C->col=B.col;
    //矩阵乘法运算
    for(int i=0;i<A.row;i++)
        for(int j=0;j<B.col;j++)
            for(int k=0;k<A.col;k++)
                C->m[i][j]+=A.m[i][k]*B.m[k][j];
    return C;
}

矩阵快速幂

这里就是将上面两个合并得到的

matrix quickPower(matrix& A,int p){    //A^p
    int n=A.col;
    //得到单位阵
    matrix ans(n,n);
    //ans=E
    FF(i,n)
        FF(j,n)
            if(i==j)
                ans.m[i][j]=1;
            else
                ans.m[i][j]=0;
    //开始快速幂
    matrix base=A;
    while(p){
        if(p&1)
            ans=*multi(ans,base);
        base=*multi(base,base);
        p>>=1;
    }
    return ans;
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值