OIer 矩阵乘法的各种类型及应用总结

矩阵乘法的各种总结

矩阵乘法的计算规则与代码模板

为了后面方便统一,先给出一个统一的规则(虽然有其他的版本)。

有两个矩阵相乘 A × B = C A \times B = C A×B=C 当且仅当 A A A 的列数 与 B B B 的行数相等,那么 C C C 的行数则与 A A A 的行数相等, C C C 的列数 与 B B B 的列数相等

A A A 的第一行的各个数分别于 B B B 的第一列的各个数对应相乘的和 为 C C C 的第一行第一列

A A A 的第一行的各个数分别于 B B B 的第二列的各个数对应相乘的和 为 C C C 的第一行第二列

A A A 的第二行的各个数分别于 B B B 的第一列的各个数对应相乘的和 为 C C C 的第二行第一列

⋯ \cdots

其余同理

模板如下

class Matrix {
    public:
        int mx[2 * N + 5][2 * N + 5];
        int row, col;
        Matrix (int n = 0, int m = 0, bool unit = 0) {
            row = n;
            col = m;
            memset(mx, 0, sizeof mx);
            if (unit && n == m) {
                for (int i = 1; i <= n; i ++) {
                    mx[i][i] = 1;
                }
            }
        }

        Matrix operator * (const Matrix& other) const {
            if (col != other.row) return Matrix(0, 0);
            Matrix result(row, other.col);
            for (int i = 1; i <= row; i ++) {
                for (int j = 1; j <= other.col; j ++) {
                    for (int k = 1; k <= col; k ++) {
                        result.mx[i][j] = (result.mx[i][j] + mx[i][k] * other.mx[k][j]) % Mod;
                    }
                }
            }
            return result;
        }

        Matrix qpow (int b) {
            if (col != row) return Matrix(0, 0);
            Matrix result (row, col, 1);
            Matrix A = (*this);
            while (b) {
                if (b & 1) result = result * A;
                A = A * A;
                b >>= 1;
            }
            return result;
        }
};

矩阵乘法优化 DP

对于形如 F n = a 1 × F n − 1 + a 2 × F n − 2 + ⋯ + a k × F n − k F_n = a_1 \times F_{n - 1} + a_2 \times F_{n - 2} + \cdots + a_k \times F_{n - k} Fn=a1×Fn1+a2×Fn2++ak×Fnkdp 方程,我们可以使用矩阵乘法进行优化。

矩阵递推的形式如下

[ 系数矩阵 ] T × [ 递推矩阵 ] = [ 答案矩阵 ] \begin{bmatrix}系数矩阵\end{bmatrix} ^ T\times \begin{bmatrix}递推矩阵\end{bmatrix}=\begin{bmatrix}答案矩阵\end{bmatrix} [系数矩阵]T×[递推矩阵]=[答案矩阵]

先忽略系数矩阵的 T T T 次方,后面会解释,我们想要知道 F n F_n Fn 显然要知道 F n − 1 , F n − 2 , ⋯   , F n − k F_{n - 1}, F_{n - 2}, \cdots, F_{n - k} Fn1,Fn2,,Fnk 因此递推矩阵中一定含有这几项,那么答案矩阵由递推矩阵得来显然与递推矩阵形式一致,因此我们可以填上一下两个矩阵

$$
\begin{bmatrix}&&&&&\&系&数&矩&阵\&&&&&\\end{bmatrix} \times \begin{bmatrix}F_{n - 1}\F_{n - 2}\F_{n - 3}\\cdots \F_{n - k}\end{bmatrix} =\begin{bmatrix}F_n\F_{n - 1}\F_{n - 2}\\cdots \F_{n - k + 1}\end{bmatrix}

$$

并且根据矩阵乘法规则,我们可以知道系数矩阵的大小为 k ∗ k k * k kk 的,现在我们要构造这个矩阵

[ A 1 , 1 A 1 , 2 ⋯ A 1 , k ⋯ ⋯ ⋯ ⋯ ] × [ F n − 1 F n − 2 F n − 3 ⋯ F n − k ] = [ F n F n − 1 F n − 2 ⋯ F n − k + 1 ] \begin{bmatrix}A_{1,1} & A_{1,2} & \cdots & A_{1,k} \\\cdots & \cdots & \cdots & \cdots\end{bmatrix}\times \begin{bmatrix}F_{n - 1}\\F_{n - 2}\\F_{n - 3}\\\cdots \\F_{n - k}\end{bmatrix} =\begin{bmatrix}F_n\\F_{n - 1}\\F_{n - 2}\\\cdots \\F_{n - k + 1}\end{bmatrix} [A1,1A1,2A1,k]× Fn1Fn2Fn3Fnk = FnFn1Fn2Fnk+1

其中 A 1 , 1 × F n − 1 + A 1 , 2 × F n − 2 + ⋯ + A 1 , k × F n − k = F n A_{1,1} \times F_{n - 1} + A_{1,2} \times F_{n - 2} + \cdots + A_{1,k} \times F_{n - k} = F_n A1,1×Fn1+A1,2×Fn2++A1,k×Fnk=Fn (矩阵乘法的规则)

由递推式可知 A 1 , 1 = a 1 , A 1 , 2 = a 2 , ⋯ A 1 , k = a k A_{1,1} = a_1, A_{1,2} = a_2, \cdots A_{1,k} = a_k A1,1=a1,A1,2=a2,A1,k=ak

我们已经完成了系数矩阵第一行的构造, 接下来就很简单了

[ ⋯ ⋯ ⋯ ⋯ A 2 , 1 A 2 , 2 ⋯ A 2 , k ⋯ ⋯ ⋯ ⋯ ] × [ F n − 1 F n − 2 F n − 3 ⋯ F n − k ] = [ F n F n − 1 F n − 2 ⋯ F n − k + 1 ] \begin{bmatrix}\cdots & \cdots & \cdots & \cdots \\A_{2,1} & A_{2,2} & \cdots & A_{2,k} \\\cdots & \cdots & \cdots & \cdots\end{bmatrix}\times \begin{bmatrix}F_{n - 1}\\F_{n - 2}\\F_{n - 3}\\\cdots \\F_{n - k}\end{bmatrix} =\begin{bmatrix}F_n\\F_{n - 1}\\F_{n - 2}\\\cdots \\F_{n - k + 1}\end{bmatrix} A2,1A2,2A2,k × Fn1Fn2Fn3Fnk = FnFn1Fn2Fnk+1

因为 F n − 1 F_{n - 1} Fn1 已经在递推矩阵中出现了因此我们直接用就好了,让 A 2 , 1 A_{2,1} A2,1 1 1 1 其余全部为 0 0 0 即可。

相当于 1 × F n − 1 + 0 × F n − 2 + ⋯ + 0 × F n − k = F n − 1 1 \times F_{n - 1} + 0 \times F_{n - 2} + \cdots + 0 \times F_{n - k} = F_{n - 1} 1×Fn1+0×Fn2++0×Fnk=Fn1,剩下的 k − 2 k - 2 k2 行依次构造即可。

最后递推矩阵每乘上一个系数矩阵相当于多往后递推一位, 因此就有了前文所述的 T T T 次方。

矩阵的等比数列求和

若有一个矩阵 A A A,求 A + A 1 + A 2 + A 3 + ⋯ + A n A + A^1 + A^2 + A^3 + \cdots + A^n A+A1+A2+A3++An 的和

因为要求和,所以说和一定要在答案矩阵里,那么不妨设 S n = A + A 1 + ⋯ + A n S_n = A + A^1 + \cdots + A^n Sn=A+A1++An,则递推式相当于 S n = S n − 1 × A + A S_n = S_{n - 1} \times A + A Sn=Sn1×A+A

构造矩阵 (过程略) 得:

[ A U n i t 1 U n i t 0 U n i t 1 ] × [ S n − 1 A ] = [ S n A ] \begin{bmatrix}A & Unit_1 \\Unit_0 & Unit_1\end{bmatrix}\times\begin{bmatrix}S_{n - 1} \\A\end{bmatrix} =\begin{bmatrix}S_n \\A\end{bmatrix} [AUnit0Unit1Unit1]×[Sn1A]=[SnA]

其中 U n i t 1 Unit_1 Unit1 是左上至右下对角线为 1 1 1 的单位矩阵, U n i t 0 Unit_0 Unit0 是一个全零矩阵,他们的大小都是与 A A A 相同的,相当于扩大了一倍

与上同理快速幂转移。

矩阵乘法在图论中的应用

其实,当我们用邻接矩阵存图的时候相当于构造了一个 n × n n \times n n×n的矩阵,那么这个矩阵自乘一次有什么意义呢?

我们来看一下 F l o y d 算法 Floyd 算法 Floyd算法:

for (int k = 1; k <= n; k ++) {
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++) {
            dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
        }
    }    
}

发现它和矩阵乘法很像,其实如果我们把这个更新的结果放在一个新的数组而不是 d i s dis dis 那么我们会得到一个 类 F l o y d 算法 类 Floyd算法 Floyd算法 可以通过矩阵快速幂实现 O ( l o g N ) O(logN) O(logN) 的得到 i i i j j j 恰好经过 N N N 条边的最短路

现在我们在改一下 d i s dis dis 的定义:

d i s i , j 表示从 i 到 j 的方案数 dis_{i,j} 表示从 i 到 j 的方案数 disi,j表示从ij的方案数

那么 F l o y d 算法 Floyd 算法 Floyd算法就应该写成这样

for (int k = 1; k <= n; k ++) {
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++) {
            dis[i][j] = dis[i][j] + dis[i][k] * dis[k][j];
        }
    }    
}

标准的矩阵乘法形式

那么 类 F l o y d 算法 类 Floyd 算法 Floyd算法 同理可以维护: i i i j j j 恰好经过 N N N 条边的方案数

那么,如果我们相求 i i i j j j 恰好经过 ≤ N \leq N N 条边的方案数

你应该已经想到了,这不就是答案矩阵 A A A A + A 1 + A 2 + A 3 + ⋯ + A N A + A^1 + A^2 + A^3 + \cdots + A^N A+A1+A2+A3++AN 吗?

上面的做法时空是 O ( 4 N ) O(4N) O(4N) 的, 其实还有一种更好的方法

[ d i s 1 , 1 d i s 1 , 2 d i s 1 , 3 ⋯ d i s 1 , n 0 d i s 2 , 1 d i s 2 , 2 d i s 2 , 3 ⋯ d i s 2 , n 0 ⋯ ⋯ ⋯ ⋯ ⋯ 0 d i s n , 1 d i s n , 2 d i s n , 3 ⋯ d i s n , n 0 1 0 0 ⋯ 0 1 ] \begin{bmatrix}dis_{1,1} & dis_{1,2} & dis_{1,3} & \cdots & dis_{1, n} & 0 \\dis_{2,1} & dis_{2,2} & dis_{2,3} & \cdots & dis_{2, n} & 0 \\\cdots & \cdots & \cdots & \cdots & \cdots & 0 \\dis_{n,1} & dis_{n,2} & dis_{n,3} & \cdots & dis_{n, n} & 0 \\1 & 0 & 0 & \cdots & 0 & 1\end{bmatrix} dis1,1dis2,1disn,11dis1,2dis2,2disn,20dis1,3dis2,3disn,30dis1,ndis2,ndisn,n000001

多添一行一列 0 0 0 在矩阵的最后,然后将起始点的对应列的最后一个修改为 1 1 1 如图则表示从 1 1 1 号点出发,矩阵的右下角设为 1 1 1

这个 1 1 1 是可以修改的。同理让矩阵自乘 N N N次即可。

最后的答案就在终点的对应列的最后一行

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值