矩阵运算

矩阵乘法

1.矩阵加减法

矩阵加减法就是将矩阵对应位置的数相加减。

\(A,B,C\) 均为 \(N\times M\) 矩阵,则 \(C=A\pm B \iff i\in [1,N],j\in [1,M]\)

\[\large C_{i,j}=A_{i,j}\pm B_{i,j} \]

例如:

\(\begin {pmatrix} 1&2 \\ 3&4 \end {pmatrix}+\begin{pmatrix} 4&3\\2&1\end {pmatrix}=\begin {pmatrix} 5&5\\5&5\end {pmatrix}\)

\(\begin{pmatrix} 3&2\\4&5\\1&2 \end{pmatrix}- \begin{pmatrix} 1&1\\1&1\\1&1 \end{pmatrix}=\begin{pmatrix} 2&1\\3&4\\0&1 \end{pmatrix}\)

矩阵加减法满足交换律,即 \(A+B=B+A\) 。满足结合律,即 \((A+B)+C=A+(B+C)\) 。满足减法的基本性质,即 \(A-B-C=A-(B+C)\)

2.矩阵乘法

矩阵乘法定义略微复杂。

\(A\)\(n\times m\) 矩阵,\(B\)\(m\times q\) 矩阵。

\(C=A\times B\)\(n\times q\) 矩阵,且 \(i\in[1,n],j\in[i,p]\)

\[\large C_{i,j}=\sum^{m}_{k=1}{A_{i,k}\times B_{k,j}} \]

例如:

\(\begin{pmatrix} 1&1&1\\1&1&1 \end{pmatrix}\times \begin{pmatrix} 1&1\\1&1\\1&1 \end{pmatrix}=\begin{pmatrix} 3&3\\3&3 \end{pmatrix}\)

\(\begin{pmatrix} 1&1\\1&1\\1&1 \end{pmatrix}\times \begin{pmatrix} 1&1&1\\1&1&1 \end{pmatrix}=\begin{pmatrix} 2&2&2\\2&2&2\\2&2&2 \end{pmatrix}\)

矩阵乘法满足结合律,即 \((A\times B)\times C=A\times (B\times C)\) 。满足分配律,即 \((A+B)\times C=A\times C+B\times C\) 。不满足交换律,即 \(A\times B\ne B\times A\;(A\ne B)\)

例题1、矩阵乘法

题意:给定两个矩阵 \(A,B\) ,计算 \(A\times B\) 的值。(数据保证 \(A\) 矩阵的行数等于 \(B\) 矩阵的列数)

分析:只需按照矩阵乘法的定义模拟即可:

#include<iostream>
using namespace std;
int a[101][101],b[101][101],ans[101][101],n,m,k; 
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<=k;j++){
            scanf("%d",&b[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++){
            for(int k=1;k<=m;k++){
                ans[i][j]+=a[i][k]*b[k][j];
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=k;j++){
            printf("%d ",ans[i][j]);
        }
        puts("");
    }
    return 0;
}

例题二、矩阵快速幂

给定 \(n\times n\) 矩阵 \(A\) ,计算 \(A^k\) 的值。

只需重载运算符即可:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
const int mo=1e9+7;
ll n,k;
struct bfs{
    ll c[200][200];
};
bfs A,ans;
bfs operator*(const bfs &x,const bfs &y){
    bfs a;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            a.c[i][j]=0;
        }
    }
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                a.c[i][j]+=x.c[i][k]*y.c[k][j]%mo;
                a.c[i][j]%=mo;
            }
        }
    }
return a;
}
int main(){
    cin>>n>>k;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>A.c[i][j];
        }
    }
    //memset(ans.c,1,sizeof(ans.c));
    for(int i=1;i<=n;i++)ans.c[i][i]=1;
    for(;k;k>>=1){
        if(k&1)ans=ans*A;
        A=A*A;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cout<<ans.c[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}

3.矩阵乘法加速递推

例题三、斐波那契数列

给定 \(n\) ,求斐波那契数列的第 \(n\)\(mod\,10^9+7\) 的值,其中 \(n\le 2^{63}-1\)

本题的弱化版是一个经典的递推问题,但是本题的 \(n\) 过大,尽管如此,本题使用递推求解还是很稳定。

\[\Huge 稳定 TLE \]

考虑矩阵优化,推出 \(fib_n\) 只需要知道 \(fib_{n-1}\) 以及 \(fib_{n-2}\)

因此,定义数组 \(a_{2,2}\) 为:

\[\large \begin{pmatrix} 0&1\\1&1 \end{pmatrix} \]

再定义数组 \(f_2\) 为:

\[\large \begin{pmatrix} 0&1 \end{pmatrix} \]

\(f\times a^{n}\) 得:

\[\large \begin{pmatrix} fib_n&fib_n+1 \end{pmatrix} \]

只需快速幂计算上述式子即可,

时间复杂度 \(O(2^3log\,n)\)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mo=1e9+7;
ll a[3][3]={{0,0,0},{0,0,1},{0,1,1}},f[3]={0,0,1},n;
void mul(){
    ll c[3]={0};
    for(int j=1;j<=2;j++){
        for(int k=1;k<=2;++k){
            c[j]=(c[j]+f[k]*a[k][j]%mo)%mo;
        }
    }
    memcpy(f,c,sizeof(c));
}
void mul2(){
    ll c[3][3]={0};
    for(int i=1;i<=2;i++){
        for(int j=1;j<=2;j++){
            for(int k=1;k<=2;++k){
                c[i][j]=(c[i][j]+a[i][k]*a[k][j]%mo)%mo;
            }
        }
    }
    memcpy(a,c,sizeof(c));
} 
int main(){
    cin>>n;
    for(;n;n>>=1){
        if(n&1) mul();
        mul2();
    }
    printf("%lld\n",f[1]);
    return 0;
} 

一般来说,若一个问题满足下述条件:

  • 可抽象成一个长度为 \(n\) 的一维向量。

  • 变化形式属于线性递推。

  • 递推轮数长,但 \(n\) 本身不大。

就能考虑使用矩阵乘法优化。

posted @ 2024-07-17 01:06  cannotmath  阅读(52)  评论(1编辑  收藏  举报