矩阵与矩阵快速幂
矩阵与矩阵快速幂
概念
定义:矩阵(Matrix)是由 行(Row) 和 列(Column) 组成的 二维矩形数组,其中每个元素称为矩阵的元素(Element)。元素的类型任意。
表示形式:
一个 \(m\times n\) 矩阵(\(m\) 行,\(n\) 列)通常用大写字母表示,例如 \(A\),写作:
其中 \(a_{ij}\) 表示矩阵 \(A\) 中第 \(i\) 行,第 \(j\) 列的元素。
同型矩阵:两个矩阵的行数和列数必须完全相同(即维度相同)。
特殊矩阵
零矩阵
定义:所有元素均为 \(0\) 的矩阵,记作 \(O_{m\times n}\)
性质:
- 加法单位元:\(A + O = A\)
- 乘法吸收性:\(AO=O\)
表示:
单位矩阵
定义:主对角线元素为 \(1\) ,其它元素均为 \(0\) 的方矩阵,记作 \(I_{n}\)
性质:
- 乘法单位元:\(AI = A,IA=A\)
- 可逆性:\(I^{-1}=I\)
表示:
矩阵的运算
令 \(A = \begin{bmatrix}a_1&a_2\\a_{3}&a_{4}\\\end{bmatrix}\),\(B = \begin{bmatrix}b_1&b_2\\b_{3}&b_{4}\\\end{bmatrix}\)。
矩阵加法
条件:同型矩阵
运算规则:对应元素相加 \((A+B)_{ij}=A_{ij}+B_{ij}\)
性质:
- 交换律:\(A+B=B+A\)
- 结合律:\(A+B+C=A+(B+C)\)
for (int i = 1;i <= A.n;i ++) for (int j = 1;j <= A.m;j ++) C[i][j] = A[i][j] + B[i][j];
矩阵减法
条件:同型矩阵
运算规则:对应元素相减 \((A-B)_{ij}=A_{ij}-B_{ij}\)
for (int i = 1;i <= A.n;i ++) for (int j = 1;j <= A.m;j ++) C[i][j] = A[i][j] - B[i][j];
标量乘法
运算规则:一个标量依次乘上所有元素 \((kA)_{ij}=kA_{ij}\)
性质:分配律:\(k(A+B)=kA+kB\)
for (int i = 1;i <= A.n;i ++) for (int j = 1;j <= A.m;j ++) C[i][j] = A[i][j] * k;
矩阵乘法
条件:维度匹配:若 \(A\) 是 \(m\times n\) 矩阵,\(B\) 是 \(n\times p\) 矩阵,则乘积 \(AB\) 是 \(m\times p\) 矩阵
运算规则:行 \(\times\) 列再求和 \((AB)_{ij}=\sum\limits_{k=1}^{n}a_{ik}\times a_{kj}\)
性质:
- 结合律:\((AB)C=A(BC)\)
- 分配律:\(A(B+C)=AB+AC\)
- 注意:不满足交换律 \(AB\ne BA\)
for (int i = 1;i <= n;i ++) // A 的行数
for (int j = 1;j <= m;j ++) // B 的列数
for (int k = 1;k <= p;k ++) // B 的行数/A 的列数
C[i][j] += A[i][k] * B[k][j];
矩阵的幂
条件:行数列数相同
运算规则:同矩阵乘法
矩阵快速幂:
Matrix pow(Matrix A,ll p) {
Matrix B(2);
for (int i = 1;i <= B.n;i ++) B[i][i] = 1ll; // 单位矩阵
while (p) {
if (p & 1) B = B * A; // 矩阵乘法,下同
A = A * A;
p = p >> 1;
}
return B;
}
矩阵及矩阵快速幂模板代码:
const int maxn = 105;
const ll mod = 1e9 + 7;
struct Matrix {
ll a[maxn + 5][maxn + 5];
int n;
Matrix (int _n) {
memset(a,0,sizeof(a));
n = _n;
}
friend Matrix operator * (Matrix A,Matrix B);
friend Matrix operator ^ (Matrix A,ll p);
};
Matrix operator * (Matrix A,Matrix B) { // 乘法
Matrix C(A.n);
for (int i = 1;i <= A.n;i ++)
for (int j = 1;j <= A.n;j ++)
for (int k = 1;k <= A.n;k ++)
C.a[i][j] = (C.a[i][j] % mod + (A.a[i][k] % mod * B.a[k][j] % mod) % mod) % mod;
return C;
}
Matrix operator ^ (Matrix A,ll p) { // 快速幂
Matrix C(2);
for (int i = 1;i <= C.n;i ++) C.a[i][i] = 1ll;
while (p) {
if (p & 1) C = C * A;
A = A * A;
p = p >> 1;
}
return C;
}
矩阵快速幂的应用
加速递推
例:求斐波那契数列第 \(n\) 项对 \(10^9+7\) 取模的结果(\(1\le n\le 10^{18}\))
观察递推式 \(f(n) = f(n-1)+f(n-2)\),将它写为矩阵的形式:
如何通过矩阵运算将矩阵 \(A\) 转换为矩阵 \(B\) 呢?这时,我们可以用矩阵乘法
设 \(P=\begin{bmatrix} a&b\\c&d \end{bmatrix}\\\)
已知 \(AP=B\)
且
所以:
显然,\(a=b=c=1,d=0\)
所以 \(P=\begin{bmatrix} 1&1\\1&0 \end{bmatrix}\\\)
将乘法操作连续进行可以得到:\(f(n)=AP^{n-2}\)
其中 \(A\) 为初始矩阵:\(f(1)=f(2)=1\)
可以发现:\(P\) 的第一列为递推式系数,后面的列则是决定保留前一个式子中的项
// 矩阵模板(省)……
Matrix A(2),B(2);
void init() { // A初始矩阵和B变换矩阵
A.a[1][1] = A.a[1][2] = 1ll;
B.a[1][1] = B.a[1][2] = B.a[2][1] = 1ll;
}
int main() {
init();
ll n; scanf("%lld",&n);
if (n <= 2ll) {
printf("1");
return 0;
}
B = B ^ (n - 2ll); // 求解
A = A * B;
printf("%lld",A.a[1][1]);
return 0;
}
路径方案数
例:给定一个有向图,求两点之间经过 \(m\) 条边到达的总方案数(可重复走)
我们先将有向图转化为邻接矩阵 \(G\),这时 \(G_{ij}\) 表示从 \(i\) 到 \(j\) 的连通情况
当 \(m = 1\) 时:\(i\rightarrow j\) 的路径条数正好是 \(G_{ij}\),也就是直连点。
当 \(m = 2\) 时:\(i\rightarrow k\rightarrow j\) 经过中间节点 \(k\),路径方案数为 (\(i\rightarrow k\) 的方案数)\(\times\)(\(k\rightarrow j\) 的方案数),而 \(k\) 可以是任意节点,所以:
这个式子则与矩阵乘法完全相同
再进行推导,当 \(m=m\) 时:\(i\rightarrow k\rightarrow j\),先经过 \(m-1\) 步到达 \(k\),再从 \(k\) 到达 \(j\),显然这两个量都是已知的。
综上,\(i\rightarrow j\) 的方案数为 \((G^m)_{ij}\)
// 矩阵模板(省)……
int n,m;
ll t;
int main() {
scanf("%d %d",&n,&m);
Matrix A(n);
for (int i = 1;i <= m;i ++) {
int u,v; scanf("%d %d",&u,&v);
A.a[u][v] = 1ll;
}
scanf("%lld",&t); // 走 t 步
A = A ^ t;
for (int i = 1;i <= A.n;i ++) {
for (int j = 1;j <= A.n;j ++) printf("%lld ",A.a[i][j]);
printf("\n");
}
return 0;
}

浙公网安备 33010602011771号