1、应用场景
已知方阵 A m × m A_{m\times m} Am×m,计算它的 n n n次幂,即 A n A^n An.
2、 矩阵快速幂计算原理
为了更快地计算 A n A^n An而不用从 1 1 1到 n n n进行遍历计算 A , A 2 , A 3 , ⋯ , A n A,A^2,A^3,\cdots ,A^n A,A2,A3,⋯,An,我们可以考虑计算 2 2 2的幂对应的次方。
-
n = 2 k n=2^k n=2k时,我们只需要计算 A , A 2 , A 4 , ⋯ , A n A, A^2,A^4,\cdots ,A^n A,A2,A4,⋯,An,计算次数只有 k k k次。
例如: n = 16 n=16 n=16时,我们只需要计算 A , A 2 , A 4 , A 8 , A 16 A,A^2,A^4,A^8,A^{16} A,A2,A4,A8,A16,计算次数为4次。 -
n n n不为 2 2 2的整数幂时,将 n n n写成 2 2 2的整数幂的和,即令 n = 2 k 1 + ⋯ + 2 k x n=2^{k_1}+\cdots +2^{k_x} n=2k1+⋯+2kx 。则 A n = A 2 k 1 ∗ ⋯ ∗ A 2 k x A^n=A^{2^{k_1}}*\cdots *A^{2^{k_x}} An=A2k1∗⋯∗A2kx。
例如: n = 20 n=20 n=20时,令 n = 2 4 + 2 2 n=2^4+2^2 n=24+22,则我们也是需要计算 A , A 2 , A 4 , A 8 , A 16 A,A^2,A^4,A^8,A^{16} A,A2,A4,A8,A16,然后需要再多一次计算 A 4 ∗ A 16 A^4*A^{16} A4∗A16。这个过程是在计算过程中完成的,并不需要记录 A 4 A^4 A4在结尾时再来计算。
总的来说,就是利用 2 2 2的幂的良好性质来完成计算,时间复杂度为 O ( log n ) O(\log n) O(logn),而直接从 1 1 1到 n n n计算的时间复杂度为 O ( n ) O(n) O(n),提升较大。
3、计算代码模板
因为是利用 2 2 2的幂,所以要使用 n n n的二进制的性质进行计算。
//计算矩阵A的n次幂
result = I; //I为A的同阶单位矩阵,记录最后的结果
while(n>0){
if(n & 1==1) //等于1表明达到一个2的整数幂,将其乘到结果中去
result = result * A;
n>>=1; //每次n右移移位
A=A*A; //计算A的2的整数幂次方
}
4、示例
计算
A
n
A^n
An,其中:
A
=
[
1
2
3
1
0
2
6
3
2
]
A=\left[ \begin{matrix} 1 & 2 &3\\ 1&0&2\\6&3&2 \end{matrix} \right]
A=⎣⎡116203322⎦⎤
c++代码如下:
#include<iostream>
#include<vector>
using namespace std;
#define N 3 //矩阵阶数
//矩阵乘法函数
vector<vector<long> > mulitply(vector<vector<long> >& a, vector<vector<long> >& b){
vector<vector<long> > ans(N,vector<long>(N,0));
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)
ans[i][j]+=a[i][k]*b[k][j];
return ans;
}
//快速幂计算函数
vector<vector<long> > QuickComputeMat(vector<vector<long> >& matrix, int n){
vector<vector<long> > res={{1,0,0},{0,1,0},{0,0,1}}; //计算结果记录矩阵
while(n>0){
if(n&1){
res=mulitply(res,matrix);
}
n>>=1;
matrix=mulitply(matrix,matrix); //求平方迭代
}
return res;
}
int main()
{
vector<vector<long> > A={{1,2,3},{1,0,2},{6,3,2}}; //需要计算的矩阵
int n=10; //次方数
vector<vector<long> > result=QuickComputeMat(A,n);
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
cout<<result[i][j]<<" ";
cout<<endl;
}
cout<<endl;
return 0;
}
5、应用
[1] 计算第 N 个泰波那契数