算法习题——矩阵

Posted 黑大帅之家

tags:

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

Q1(poj 3070):

求斐波那契数列的第n个,n最大取到1000000000,

分析:求这种较大递推数列的一般方法使用矩阵快速幂的,这里题目直接给出了矩阵形式,就不需要进行友矩阵(A)的构造了,也不需要进行最后一次矩阵和向量的相乘,直接初始化矩阵规模,进行快速幂即可。

不过这个结论倒是可以记住,以后就有了logn求斐波那契数列的方法:

参考代码如下:

 

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

const int maxn = 20;
typedef long long Matrix[maxn][maxn];
typedef long long Vector[maxn];

int sz , mod;
void matrix_mul(Matrix A , Matrix B , Matrix res)//矩阵A*B = C , O(n^3).矩阵均为同阶方阵
{
     Matrix C;
     memset(C , 0 , sizeof(C));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz; j++)
             for(int k = 0;k < sz; k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j])%mod;

     memcpy(res , C , sizeof(C));
}
void matrix_pow(Matrix A , int n , Matrix res)//矩阵快速幂O(logn)
{
    Matrix a , r;
    memcpy(a , A , sizeof(a));
    memset(r , 0 , sizeof(r));
    for(int i = 0;i < sz;i++)  r[i][i] = 1;//单位矩阵
    while(n){
        if(n&1)  matrix_mul(r , a , r);
        n >>= 1;
        matrix_mul(a , a , a);
    }
    memcpy(res , r , sizeof(r));
}

void Transform(Vector d , Matrix A , Vector res)//计算完A^(n-d)之后,这个函数计算A*d = res
{
     Vector r;
     memset(r , 0 , sizeof(r));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz;j++)
              r[i]  = (r[i] + d[j] * A[i][j])%mod;

     memcpy(res , r , sizeof(r));
}

int main()
{
    int  n;
    while(cin >>n)
    {
         if(n == -1) break;
         if(n == 0) {cout<<0<<endl;continue;}

         mod = 10000;
         sz = 2;

         Vector a , f;
         Matrix A;
         memset(A , 0 , sizeof(A));
         A[0][0] = 1;
         A[0][1] = 1;
         A[1][0] = 1;
         A[1][1] = 0;

         matrix_pow(A , n - 1 , A);
         cout << A[0][0] << endl;
    }
    return 0;
}

 

 

Q2(hdu 5950):

一个数列的递推关系式是f[i] = f[i-1] + 2f[i-2] + i^4,现在给出n(最大可取1000000000),计算f[n]%mod的结果。

分析:这道题的核心方法就是上面我们提到的时间复杂度为O(logn)求递推关系的矩阵快速幂。而这个方法的关键就是快速幂的底数A,需要一定的推导技巧。

#include<iostream>
#include<string>
#include<cstring>
using namespace std;

const int maxn = 20;
typedef long long Matrix[maxn][maxn];
typedef long long Vector[maxn];

int sz ;
long long mod = 2147493647;
void matrix_mul(Matrix A , Matrix B , Matrix res)//矩阵A*B = C , O(n^3).矩阵均为同阶方阵
{
     Matrix C;
     memset(C , 0 , sizeof(C));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz; j++)
             for(int k = 0;k < sz; k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j])%mod;

     memcpy(res , C , sizeof(C));
}
void matrix_pow(Matrix A , int n , Matrix res)//矩阵快速幂O(logn)
{
    Matrix a , r;
    memcpy(a , A , sizeof(a));
    memset(r , 0 , sizeof(r));
    for(int i = 0;i < sz;i++)  r[i][i] = 1;//单位矩阵
    while(n){
        if(n&1)  matrix_mul(r , a , r);
        n >>= 1;
        matrix_mul(a , a , a);
    }
    memcpy(res , r , sizeof(r));
}

void Transform(Vector d , Matrix A , Vector res)//计算完A^(n-d)之后,这个函数计算A*d = res
{
     Vector r;
     memset(r , 0 , sizeof(r));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz;j++)
              r[i]  = (r[i] + d[j] * A[i][j])%mod;

     memcpy(res , r , sizeof(r));
}

int main()
{
    long long n , a , b;

     int t;
     cin>>t;
    while(t--)
    {
       cin>>n>>a>>b;
      sz = 7;             //矩阵A的规模是sz
      Vector  f;
      if(n == 1) {cout<<a<<endl;continue;}
      if(n == 2) {cout<<b<<endl;continue;}
         f[0] = b;f[1] = a;
         f[2] = 16;f[3] = 8;f[4] = 4;f[5] = 2;f[6] = 1;

     Matrix A;
     memset(A , 0 , sizeof(A));//注意每次矩阵A的参数都要初始化.
     A[0][0] = 1;A[0][1] = 2;A[0][2] = 1;A[0][3] = 4;A[0][4] = 6;A[0][5] = 4;A[0][6] = 1;
     A[1][0] = 1;
     A[2][2] = 1;A[2][3] = 4;A[2][4] = 6;A[2][5] = 4;A[2][6] = 1;
     A[3][3] = 1;A[3][4] = 3;A[3][5] = 3;A[3][6] = 1;
     A[4][4] = 1;A[4][5] = 2;A[4][6] = 1;
     A[5][5] = 1;A[5][6] = 1;
     A[6][6] = 1;

         matrix_pow(A , n - 2 , A);
         Transform(f , A , f);

         cout << f[0] << endl;
    }
    return 0;
} 

Q3(uva 10689):

 这道题目是矩阵快速幂求斐波那契数列的推广形式,给出f[0],f[1]的初值,递推关系式斐波那契数列的递推关系f[n]=f[n-1]+f[n-2].

  分析:由于递推关系和斐波那契数列的递推关系一致,友矩阵Q是一样的.

 

 

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
using namespace std;

const int maxn = 20;
typedef long long Matrix[maxn][maxn];
typedef long long Vector[maxn];

int sz , mod;
void matrix_mul(Matrix A , Matrix B , Matrix res)//矩阵A*B = C , O(n^3).矩阵均为同阶方阵
{
     Matrix C;
     memset(C , 0 , sizeof(C));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz; j++)
             for(int k = 0;k < sz; k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j])%mod;

     memcpy(res , C , sizeof(C));
}
void matrix_pow(Matrix A , int n , Matrix res)//矩阵快速幂O(logn)
{
    Matrix a , r;
    memcpy(a , A , sizeof(a));
    memset(r , 0 , sizeof(r));
    for(int i = 0;i < sz;i++)  r[i][i] = 1;//单位矩阵
    while(n){
        if(n&1)  matrix_mul(r , a , r);
        n >>= 1;
        matrix_mul(a , a , a);
    }
    memcpy(res , r , sizeof(r));
}

void Transform(Vector d , Matrix A , Vector res)//计算完A^(n-d)之后,这个函数计算A*d = res
{
     Vector r;
     memset(r , 0 , sizeof(r));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz;j++)
              r[i]  = (r[i] + d[j] * A[i][j])%mod;

     memcpy(res , r , sizeof(r));
}

int main()
{
   int a , b , m , n;
   int t;
   cin>>t;
   while(t--)
  {
      cin >> a >> b >> n >>m;
      mod = 10;
      sz = 2;
      for(int i = 1;i < m;i++)
             mod *= 10;

      Vector  f;
      Matrix A;


       f[1] = a;
       f[0] = b;
         //列向量[f(d) , f(d-1) , f(d-2) , ... , f(1)]

       memset(A , 0 , sizeof(A));//得到配出来的常数矩阵A
       A[0][0] = 1;A[0][1] = 1;
       A[1][0] = 1;A[1][1] = 0;

       matrix_pow(A , n - 1 , A);
       Transform(f , A , f);


         cout << f[0] << endl;
  }

    return 0;
}
View Code

 

Q4(hdu4565):

 

Q5(hdu2256)

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn = 20;
typedef long long Matrix[maxn][maxn];
typedef long long Vector[maxn];

int sz , mod;
void matrix_mul(Matrix A , Matrix B , Matrix res)//矩阵A*B = C , O(n^3).矩阵均为同阶方阵
{
     Matrix C;
     memset(C , 0 , sizeof(C));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz; j++)
             for(int k = 0;k < sz; k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j])%mod;

     memcpy(res , C , sizeof(C));
}
void matrix_pow(Matrix A , int n , Matrix res)//矩阵快速幂O(logn)
{
    Matrix a , r;
    memcpy(a , A , sizeof(a));
    memset(r , 0 , sizeof(r));
    for(int i = 0;i < sz;i++)  r[i][i] = 1;//单位矩阵
    while(n){
        if(n&1)  matrix_mul(r , a , r);
        n >>= 1;
        matrix_mul(a , a , a);
    }
    memcpy(res , r , sizeof(r));
}

void Transform(Vector d , Matrix A , Vector res)//计算完A^(n-d)之后,这个函数计算A*d = res
{
     Vector r;
     memset(r , 0 , sizeof(r));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz;j++)
              r[i]  = (r[i] + d[j] * A[i][j])%mod;

     memcpy(res , r , sizeof(r));
}

int main(){
    int n , T;
    scanf("%d" , &T);
    while(T--){
         scanf("%d" , &n);
         mod = 1024;//整个数值在m的剩余系下
         sz = 2;//矩阵A的规模是sz
        if(n == 0) {printf("1\\n");continue;}
         Vector a , f;
         Matrix A;
         //A是矩阵,a是递推公式的系数向量 f是数列的初值向量
         f[0] = 1; f[1] = 0;
         //列向量[f(d) , f(d-1) , f(d-2) , ... , f(1)]
         //数学概念上向量从1开始,但是存储上f[]数组是从0开始的,这点一定要注意!!逻辑高位存储在存储结构的地位,这里非常容易错!
         memset(A , 0 , sizeof(A));//得到配出来的常数矩阵A
         A[0][0] = 5;A[0][1] = 12;
         A[1][0] = 2;A[1][1] = 5;


         matrix_pow(A , n  , A);
         Transform(f , A , f);


        printf("%d\\n" ,(2 * f[0] - 1) %mod);
    }
    return 0;
}
View Code

Q6(hdu5451):

 

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn = 20;
typedef long long Matrix[maxn][maxn];
typedef long long Vector[maxn];
typedef long long LL;
int sz , mod;
void matrix_mul(Matrix A , Matrix B , Matrix res)//矩阵A*B = C , O(n^3).矩阵均为同阶方阵
{
     Matrix C;
     memset(C , 0 , sizeof(C));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz; j++)
             for(int k = 0;k < sz; k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j])%mod;

     memcpy(res , C , sizeof(C));
}
void matrix_pow(Matrix A , int n , Matrix res)//矩阵快速幂O(logn)
{
    Matrix a , r;
    memcpy(a , A , sizeof(a));
    memset(r , 0 , sizeof(r));
    for(int i = 0;i < sz;i++)  r[i][i] = 1;//单位矩阵
    while(n){
        if(n&1)  matrix_mul(r , a , r);
        n >>= 1;
        matrix_mul(a , a , a);
    }
    memcpy(res , r , sizeof(r));
}

void Transform(Vector d , Matrix A , Vector res)//计算完A^(n-d)之后,这个函数计算A*d = res
{
     Vector r;
     memset(r , 0 , sizeof(r));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz;j++)
              r[i]  = (r[i] + d[j] * A[i][j])%mod;

     memcpy(res , r , sizeof(r));
}
LL Quick_Mod(LL a, LL b, int m){
    LL res = 1,term = a % m;
    while(b)
    {
        if(b & 1) res = (res * term) % m;
        term = (term * term) % m;
        b >>= 1;
    }
    return res%m;

}

int main(){
    int  T;
    LL x;
    scanf("%d" , &T);
    for(int kase = 1;kase <= T;kase++){
         scanf("%lld %d" , &x , &mod);
         sz = 2;//矩阵A的规模是sz
          Vector a , f;
          Matrix A;
          //A是矩阵,a是递推公式的系数向量 f是数列的初值向量
          f[0] = 1; f[1] = 0;
          x = Quick_Mod(2 , x ,  mod * mod - 1) + 1;
          if(x == 0) {printf("1\\n");continue;}

         //列向量[f(d) , f(d-1) , f(d-2) , ... , f(1)]
         //数学概念上向量从1开始,但是存储上f[]数组是从0开始的,这点一定要注意!!逻辑高位存储在存储结构的地位,这里非常容易错!
         memset(A , 0 , sizeof(A));//得到配出来的常数矩阵A
         A[0][0] = 5;A[0][1] = 12;
         A[1][0] = 2;A[1][1] = 5;


         matrix_pow(A , x , A);
         Transform(f , A , f);


        printf("Case #%d: %d\\n" ,kase , (2 * f[0] - 1) %mod);
    }
    return 0;
} 
View Code

Q7(hdu6198):

  基于斐波那契数列,给出整数k,让你计算k个允许重复的斐波那契数列,不能组成的最小整数是多少。

  分析:通过手动算找规律,编程打表找规律也好,找到规律问题的本质是让我们求fib(2n + 3)-1.然后简单一发矩阵快速幂即可。

 

 

Q8(hdu6185):

1x2的格子覆盖4xn的格子,问有多少种不同的方案,结果对1e9+7取模。

分析:这道题目算是很综合了。纯粹基于覆盖的机理找递推关系难度较大,可以通过dfs找到小数据的表,我们根据n的取值,也能够猜测这道题目应该是有线性递推的关系的。这里在拿到了前十项的数据之后,找规律有个小套路,最基本的是靠观察,但是对于含有2项以上的线性递推关系,这个方法就不是很好了。这里我们依次假设题目有如下的线性递推关系:

(1)f(n) = a*f(n-1)+b*f(n-2)

(2)f(n) = a*f(n-1)+b*f(n-2)+c*f(n-3)

(3)f(n)=a*f(n-1)+b*f(n-2)+c*f(n-3)+d*f(n-4)

...

 

然后基于原始数据,构造线性方程组再用高斯消元求解ab等参数进行验证,当得到系数均为整数的时候,即题目满足的线性递推关系。

找到了线性递推关系之后,用矩阵快速幂跑一发即可。

 

 Q9(hdu4965):

 

 

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn = 1000 + 1;
typedef long long Matrix1[maxn][6];
typedef long long Matrix2[6][maxn];
typedef long long Matrix3[6][6];


int sz , mod;
void matrix_mul(Matrix3 A , Matrix3 B , Matrix3 res)//矩阵A*B = C , O(n^3).矩阵均为同阶方阵
{
     Matrix3 C;
     memset(C , 0 , sizeof(C));
     for(int i = 0;i < sz;i++)
          for(int j = 0;j < sz; j++)
             for(int k = 0;k < sz; k++)
                C[i][j] = (C[i][j] + A[i][k] * B[k][j])%mod;

     memcpy(res , C , sizeof(C));
}

void matrix_mul_p1(Matrix2 B ,  Matrix1 A, int sz1 , int sz2, int sz3 ,  Matrix3 res){//sz1*sz2的矩阵与sz2*sz3的矩阵做乘法
       Matrix3 C;
       memset(C , 0 , sizeof(C));
       for(int i = 0;i < sz1;i++)
         for(int j = 0;j < sz3;j++)
            for(int k = 0;k < sz2;k++)
               C[i][j] = (C[i][j] + B[i][k]*A[k][j]);
         memcpy(res , C , sizeof(C));

}
void matrix_mul_p2(Matrix1 A ,  Matrix3 C, int sz1 , int sz2, int sz3 ,  Matrix1 res){//sz1*sz2的矩阵与sz2*sz3的矩阵做乘法
       Matrix1 temp;
       memset(temp , 0 , sizeof(temp));
       for(int i = 0;i < sz1;i++)
         for(int j = 0;j < sz3;j++)
            for(int k = 0;k < sz2;k++)
               temp[i][j] = (temp[i][j] + A[i][k]*C[k][j])%mod;
         memcpy(res , temp , sizeof(temp));

}

int matrix_mul_p3(Matrix1 A ,  Matrix2 B, int sz1 , int sz2, int sz3){//sz1*sz2的矩阵与sz2*sz3的矩阵做乘法
       int temp ,ans;
       temp = 0;ans = 0;
       for(int i = 0;i < sz1;i++){
         for(int j = 0;j < sz3;j++){
                temp = 0;
            for(int k = 0;k < sz2;k++)
               temp = (temp + A[i][k]*B[k][j])%mod;
            ans += temp;
         }
       }

        return ans;

}
void matrix_pow(Matrix3 A , int n , Matrix3 res)//矩阵快速幂O(logn)
{
    Matrix3 a , r;
    memcpy(a , A , sizeof(a));
    memset(r , 0 , sizeof(r));
    for(int i = 算法零基础学习关于二维数组的一些基础练习题 | leetcode1672158283248题解

算法零基础学习关于二维数组的一些基础练习题 | leetcode1672158283248题解

算法零基础学习关于二维数组的一些基础练习题 | leetcode1672158283248题解

排序练习题:有序矩阵查找

《算法零基础100讲》(第3讲) 矩阵

第二章 排序 || 第18节 有序矩阵查找练习题