ACM竞赛学习整理--矩阵运算

ACM竞赛学习整理–矩阵运算

了解矩阵类

【任务】

实现矩阵的基本变换

【接口】

结构体:Matrix

成员变量:

int n,m 矩阵大小

int a[][] 矩阵内容

重载运算符: +、-、x

成员函数:void clear() 清空矩阵

【代码】

const int MAXN = 1010;
const int MAXM = 1010;

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];
 return tmp; 
}

【扩展】

关于矩阵加速数列递推:

给定一个递推数列

f[i]=a1∗f[i−1]+a2∗f[i−2]…ak∗f[i−k] ,

我们普通计算的话肯定是逐个计算,复杂度较大。

我们可以用矩阵表示:
在这里插入图片描述

为了递推出f[n] , 我们需要找到一个系数矩阵 A 使得:

在这里插入图片描述

就可以这样计算:

在这里插入图片描述

A矩阵可以这样构造:

在这里插入图片描述

至此,我们可以愉快地用矩阵加速递推数列了。

参考来源:https://www.cnblogs.com/alecli/p/10004417.html

【应用】

poj 2663详解

Description
In how many ways can you tile a 3xn rectangle with 2x1 dominoes?
Here is a sample tiling of a 3x12 rectangle.

Input
Input consists of several test cases followed by a line containing -1. Each test case is a line containing an integer 0 <= n <= 30.

Output
For each test case, output one integer number giving the number of possible tilings.

Sample Input
2
8
12
-1

Sample Output
3
153
2131

分析题目,这是一个递推关系求解题,并且很容易发现当n为奇数时,无法找到满足题意的铺法,以下仅考虑n为偶数的情况。

思路:
这里先定义两个概念:独立单位和非独立单位。独立单位即不可纵向切割的矩形块, 非独立单位即可纵向切割的矩形块。

我们先来试试几种简单情况。当n = 2时,有3种铺法,如下图。

在这里插入图片描述

当n=4时。组合分为两种情况:一种是两个n=2的独立单位组合,另一种是一个n=0的独立单位组合上一个n=4的独立单位。分别如下图。

在这里插入图片描述

两个n=2的独立单位组合,比较简单,铺法为3x3。一个n=0的独立单位组合上一个n=4的独立单位,通过画图可以判断,只有两种情况,分别为:

在这里插入图片描述

那么n=4的总铺法数就容易确定了,为 3xa[2]+2xa[0] (这里a[0]=1,至于为什么等于1,请读者自己体会)

接下来考虑n= 6,这时有三种组合情况,分别为:

  1. 一个n=4的独立单位连接上一个n=2的独立单位;
  2. 一个n=2的独立单位连接上一个n=4的独立单位;
  3. 一个n=0的独立单位连接上一个n=6的独立单位。
    组合1:铺法为a[4]x3;
    组合2:铺法为a[2]x2;
    组合3:铺法为a[0]x2;
    故n=6时的总铺法数为:a[4]x3+a[2]x2+a[0]x2。
    (有人可能会问为什么要乘以2,这里请读者自行画图求解…)

当n更大时,以此类推。
所以最后我们得出a[n] = 3xa[n-2]+2x(a[n-4]+a[n-6] +…+a[0]),再运用高中所学数列知识,化简得:a[n] = 4a[n-2] - a[n-4];
代码整理如下:

#include<iostream>
#include<string.h>
using namespace std;
const int MAXN=10;
const int MAXM=10;

const long long mod = 1000007;
int r;
//矩阵类模板
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){
        if(r==0) break;
        int a[]= {1,0,3,0};
        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]=4;
        //A.a[3][3]=1;
        A=A.get(r-3);
        Matrix M;
        M.clear();
        M.n=4;M.m=1;
        M.a[0][0]=1;
        M.a[2][0]=3;
        M.a[3][0]=0;
        M=A*M;
        cout<<(M.a[3][0]+mod)%mod<<endl;
    }
    return 0;
}

ps: ACM国际大学生程序设计与竞赛-算法基础(俞勇主编)里有介绍矩阵的实现,刚好手上有个项目要用到矩阵的操作, 一开始想用Eigen 库来实现矩阵的操作,后来想想干脆还是C去实现吧。下午空闲一会了,找了一个ACM的例题来做做。于是就拙了一篇,请大家多指正。

原创文章 41 获赞 0 访问量 2062

猜你喜欢

转载自blog.csdn.net/qq_21291397/article/details/103804377