zoukankan      html  css  js  c++  java
  • poj 3233 Matrix Power Series(矩阵快速幂)

    Description

    Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.

    Input

    The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.

    Output

    Output the elements of S modulo m in the same way as A is given.

    Sample Input

    2 2 4
    0 1
    1 1

    Sample Output

    1 2
    2 3
    解题思路:等比矩阵求和,采用递归二分的方法。

    上图就给出了求前k项等比矩阵的和的递推式,解法采用递归来求和比较直观,也很好理解。
    AC代码(1704ms):
     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 const int maxn=35;
     5 int n,k,mod;
     6 struct Matrix{int m[maxn][maxn];}init;
     7 Matrix add(Matrix a,Matrix b){//矩阵加法
     8     Matrix c;
     9     for(int i=0;i<n;++i)
    10         for(int j=0;j<n;++j)
    11             c.m[i][j]=(a.m[i][j]+b.m[i][j])%mod;
    12     return c;
    13 }
    14 Matrix mul(Matrix a,Matrix b){//矩阵乘法
    15     Matrix c;
    16     for(int i=0;i<n;i++){
    17         for(int j=0;j<n;j++){
    18             c.m[i][j]=0;
    19             for(int k=0;k<n;k++)
    20                 c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
    21         }
    22     }
    23     return c;
    24 }
    25 Matrix quick_power(Matrix a,int x){//矩阵快速幂
    26     Matrix b;memset(b.m,0,sizeof(b.m));
    27     for(int i=0;i<n;++i)b.m[i][i]=1;//单位矩阵
    28     while(x){
    29         if(x&1)b=mul(b,a);
    30         a=mul(a,a);x>>=1;
    31     }
    32     return b;
    33 }
    34 Matrix sum(Matrix s,int k){//求前k项和
    35     if(k==1)return s;//递归出口:当幂指数为1时,返回当前的矩阵
    36     Matrix tmp;memset(tmp.m,0,sizeof(tmp.m));//暂存保存中间的矩阵
    37     for(int i=0;i<n;++i)tmp.m[i][i]=1;//单位矩阵
    38     tmp=add(tmp,quick_power(s,k>>1));//计算1+A^{k/2}
    39     tmp=mul(tmp,sum(s,k>>1));//计算(1+A^{k/2})*(A + A^2 + A^3 + … + A^{k/2})=(1+A^{k/2})*(S_{k/2})
    40     if(k&1)tmp=add(tmp,quick_power(s,k));//若k是奇数,则加上A^k
    41     return tmp;//返回前k项的值
    42 }
    43 void print_rectangle(Matrix r){
    44     for(int i=0;i<n;++i)
    45         for(int j=0;j<n;++j)
    46             cout<<r.m[i][j]<<((j==n-1)?"
    ":" ");
    47 }
    48 int main(){
    49     while(cin>>n>>k>>mod){
    50         for(int i=0;i<n;++i)
    51             for(int j=0;j<n;++j)
    52                 cin>>init.m[i][j];
    53         init=sum(init,k);
    54         print_rectangle(init);
    55     }
    56     return 0;
    57 }

     采用分块矩阵求解可以减少很多时间,具体推导可以结合下图:

    矩阵中套矩阵,效率上比上一种方法更快,实际上是2n×2n的矩阵快速幂。就样例展开等式左边的矩阵:

    那么最终的答案就是等式右边矩阵中左下角的子矩阵减去单位矩阵,注意某个元素值减-1之后可能为-1,那么此时只需再加上mod即可。

    AC代码(610ms):

     1 #include<iostream>
     2 #include<cstring>
     3 using namespace std;
     4 const int maxn=70;
     5 struct Matrix{int m[maxn][maxn];}init;
     6 int n,k,mod;
     7 Matrix mul(Matrix a,Matrix b){//矩阵乘法
     8     Matrix c;
     9     for(int i=0;i<2*n;i++){//矩阵大小扩大两倍,枚举第一个矩阵的行
    10         for(int j=0;j<2*n;j++){//枚举第二个矩阵的列
    11             c.m[i][j]=0;
    12             for(int k=0;k<2*n;k++)//枚举第一个矩阵的列
    13                 c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%mod;
    14         }
    15     }
    16     return c;
    17 }
    18 Matrix POW(Matrix a,int x){//矩阵快速幂
    19     Matrix b;memset(b.m,0,sizeof(b.m));
    20     for(int i=0;i<2*n;++i)b.m[i][i]=1;//构造单位矩阵
    21     while(x){
    22         if(x&1)b=mul(b,a);
    23         a=mul(a,a);x>>=1;
    24     }
    25     return b;
    26 }
    27 void print_rectangle(Matrix r){
    28     for(int i=0;i<n;++i){
    29         for(int j=0;j<n;++j){
    30             if(i==j)r.m[n+i][j]-=1;
    31             if(r.m[n+i][j]<0)r.m[n+i][j]+=mod;//左下角子矩阵减去单位矩阵,减完可能小于0,因此需要加上mod再取余mod
    32             cout<<r.m[n+i][j]<<((j==n-1)?'
    ':' ');
    33         }
    34     }
    35 }
    36 int main(){
    37     while(cin>>n>>k>>mod){
    38         memset(init.m,0,sizeof(init.m));//全部初始化为0
    39         for(int i=0;i<n;++i){//首先初始化矩阵
    40             for(int j=0;j<n;++j)
    41                 cin>>init.m[i][j];
    42             init.m[n+i][i]=init.m[n+i][n+i]=1;//其余是单位矩阵
    43         }
    44         init=POW(init,k+1);//求其前k+1项和(左下角包含单位矩阵,最后输出要减去单位矩阵)
    45         print_rectangle(init);//打印等比矩阵A前k项和
    46     }
    47     return 0;
    48 }
  • 相关阅读:
    JAVAWEB进行PC支付宝支付
    SpringBoot 设置请求字符串格式为UTF-8
    SpringBoot 处理跨域请求问题
    Python 包制作
    F5 开发
    CentOS7 部署nfs服务
    Debian 9 部分快捷键失效问题
    Win10提示 该文件没有与之关联的程序来执行操作
    Debian 9 编译Python
    debian 9 安装远程桌面
  • 原文地址:https://www.cnblogs.com/acgoto/p/9082806.html
Copyright © 2011-2022 走看看