矩阵快速幂算法详细解析

healthy 365 app admin 2025-07-25 17:05:16

在上一篇博客我谈到了大数的快速幂,而相对于矩阵的指数运算同样可以有方法,在此之前我们来看看矩阵的乘法:

矩阵的乘法是需要矩阵A的行数与矩阵B的列数相等的(A*B的前提条件)但矩阵快速幂一般只用到方阵(行数和列数相等的情况),从而避免了前提条件。

如:

[A11A12⋯A1nA21A22⋯A2n⋮⋮⋱⋮An1An2⋯Ann][B11B12⋯B1nB21B22⋯B2n⋮⋮⋱⋮Bn1An2⋯Ann]=[C11C12⋯C1nC21C22⋯C2n⋮⋮⋱⋮Cn1Cn2⋯Cnn]

\begin{matrix}\\

\left[

\begin{matrix}

A_{11} & A_{12} & \cdots & A_{1n} \\

A_{21} & A_{22} & \cdots & A_{2n} \\

\vdots & \vdots & \ddots & \vdots \\

A_{n1} & A_{n2} & \cdots &A_{nn} \\

\end{matrix}

\right]

\left[

\begin{matrix}

B_{11} & B_{12} & \cdots & B_{1n} \\

B_{21} & B_{22} & \cdots &B_{2n} \\

\vdots & \vdots & \ddots & \vdots \\

B_{n1} & A_{n2} & \cdots & A_{nn} \\

\end{matrix}

\right]

=&

\left[

\begin{matrix}

C_{11} & C_{12} & \cdots &C_{1n} \\

C_{21} &C_{22} & \cdots &C_{2n} \\

\vdots & \vdots & \ddots & \vdots \\

C_{n1} &C_{n2} & \cdots &C_{nn} \\

\end{matrix}

\right]

\end{matrix}

⎣⎢⎢⎢⎡​A11​A21​⋮An1​​A12​A22​⋮An2​​⋯⋯⋱⋯​A1n​A2n​⋮Ann​​⎦⎥⎥⎥⎤​⎣⎢⎢⎢⎡​B11​B21​⋮Bn1​​B12​B22​⋮An2​​⋯⋯⋱⋯​B1n​B2n​⋮Ann​​⎦⎥⎥⎥⎤​=​⎣⎢⎢⎢⎡​C11​C21​⋮Cn1​​C12​C22​⋮Cn2​​⋯⋯⋱⋯​C1n​C2n​⋮Cnn​​⎦⎥⎥⎥⎤​​

根据线性代数的知识我们也容易知道,俩个矩阵相乘,前提是A的行数与B的列数相等,结果是其在新矩阵的行所对应的A的行与在新矩阵的列所对应的B的列对应相乘相加,所以我们可以先得出矩阵乘法的代码:

for(i=1;i<=n;i++)

{

for(j=1;j<=n;j++)

{

for(k=1;k<=n;k++)

{

c[i][j] = c[i][j] + a[i][k] * b[k][j];

}

}

}

所以我们给出例子:

假如有一个n * n的方阵A,所谓的方阵就是行数与列数相等的矩阵,给出数M,求矩阵A的M次幂A^M

这个例子就很直接了,就是直接求矩阵的M次幂,结合快速幂算法和矩阵相乘可以得出代码:

#include

#include

#include

using namespace std;

int M,n;

struct node//定义一个矩阵类型的结构体

{

int m[100][100];

} ans,res;//ans是结果,res是最初的方阵

node mul(node A,node B)

{

int i,j,k;

node temp;//定义一个临时矩阵,存放A*B的结果

for(i=0; i

{

for(j=0; j

{

temp.m[i][j] = 0;

}

}

for(i=0; i

{

for(j=0; j

{

for(k=0; k

{

temp.m[i][j] += A.m[i][k] * B.m[k][j];

}

}

}

return temp;

}

void quickpower(int M,int n)

{

int i,j;

for(i=0; i

{

for(j=0; j

{

if(i == j)

{

ans.m[i][j] = 1;

}

else

ans.m[i][j] = 0;

}

}//这里是思想的转换,之前我们定义为1去计算,所以我们先初始化ans为

//单位矩阵,我们知道单位矩阵与任何矩阵的乘积为其本身

while(M)//快速幂的步骤

{

if(M & 1)

{

ans = mul(ans,res);

}

res = mul(res,res);

M = M >> 1;

}

}

int main()

{

cin>>n;//方阵的阶数

cin>>M;//指数

int i,j;

for(i=0; i

{

for(j=0; j

{

cin>>res.m[i][j];//初始化方阵res

}

}

quickpower(M,n);//进行快速幂

for(i=0; i

{

for(j=0; j

{

printf("%d ",ans.m[i][j]);

}

printf("\n");

}

return 0;

}

以上就是矩阵快速幂的思路与代码,但是一般的题并不会简单的让你去求矩阵的快速幂,其通常是与斐波那切数相结合,我们知道最简单的斐波那切的函数就是f(n)=f(n-1)+f(n-2)(当然不清楚的伙伴可以先去了解一下斐波那切数),倘若n很大的情况用快速矩阵可以得到:

[f(n)f(n−1)]=[1110][f(n−1)f(n−2)]=[1110]n−2[f(2)f(1)]

\begin{matrix}\\

\left[

\begin{matrix}

f(n) \\

f(n-1) \\

\end{matrix}

\right]

=&

\left[

\begin{matrix}

1 & 1 \\

1 & 0 \\

\end{matrix}

\right]

\left[

\begin{matrix}

f(n-1) \\

f(n-2) \\

\end{matrix}

\right]

=&

\left[

\begin{matrix}

1 & 1 \\

1 & 0 \\

\end{matrix}

\right]^{n-2}

\left[

\begin{matrix}

f(2) \\

f(1) \\

\end{matrix}

\right]

\end{matrix}

[f(n)f(n−1)​]=​[11​10​][f(n−1)f(n−2)​]=​[11​10​]n−2[f(2)f(1)​]​

原式斐波那切可以转换为矩阵相乘,然而不断推演下去就是求这个矩阵的n-2次方,当然有时也有其他形式f(n)=af(n-1) +bf(n-2) + c:

[f(n)f(n−1)c]=[ab1100001][f(n−1)f(n−2)c]

\begin{matrix}\\

\left[

\begin{matrix}

f(n) \\

f(n-1) \\

c\\

\end{matrix}

\right]

=&

\left[

\begin{matrix}

a &b &1 \\

1 & 0 &0 \\

0 & 0&1\\

\end{matrix}

\right]

\left[

\begin{matrix}

f(n-1) \\

f(n-2) \\

c\\

\end{matrix}

\right]

\end{matrix}

⎣⎡​f(n)f(n−1)c​⎦⎤​=​⎣⎡​a10​b00​101​⎦⎤​⎣⎡​f(n−1)f(n−2)c​⎦⎤​​

f(n) = cn - f(n-1):

[f(n)cn]=[−1c0c][f(n−1)cn−1]

\begin{matrix}\\

\left[

\begin{matrix}

f(n) \\

c^n\\

\end{matrix}

\right]

=&

\left[

\begin{matrix}

-1 &c \\

0 & c \\

\end{matrix}

\right]

\left[

\begin{matrix}

f(n-1) \\

c^{n-1}\\

\end{matrix}

\right]

\end{matrix}

[f(n)cn​]=​[−10​cc​][f(n−1)cn−1​]​

下面给出一个例子:

勇者龙宫院圣哉与n名冒险者一起去讨伐神秘魔物,龙宫院圣哉十分谨慎,他只会在最后一刻出手,每名冒险者轮流攻击魔物,冒险者的攻击有着某种规律,目前造成的总伤害是上一名冒险者攻击后造成的总伤害的4倍与上上名冒险者攻击后造成的总伤害的3倍之和,即当前总伤害f(n)=4f(n-1)+3f(n-2)(魔物的奇怪设定使总伤害忽高忽低),又由于异世界的奇异设定,冒险者们的总伤害不会超过666666,即对666666取模,龙宫院圣哉清楚的知道这个魔物的血量为m(m>666666),他想知道在所有的冒险者攻击完了以后,自己需要造成多少点伤害才能杀死魔物?目前第一名冒险者攻击后总共造成了4点伤害,第二名冒险者攻击后总共造成了233点伤害。2

输入 3

666667

输出 665723

这个很明显是矩阵快速幂,f(n)=4f(n-1)+3f(n-2)

#include

#include

#include

using namespace std;

struct node

{

long long int m[10][10];

}ans,res;

node mul(node A,node B)

{

int i,j,k;

node temp;//定义一个临时矩阵,存放A*B的结果

for(i=0; i

{

for(j=0; j

{

temp.m[i][j] = 0;

}

}

for(i=0; i

{

for(j=0; j

{

for(k=0; k

{

temp.m[i][j] += (A.m[i][k] * B.m[k][j])%666666;//取模

}

}

}

return temp;

}

node quickpower(node a,long long n)

{

node c;

memset(c.m,0,sizeof(c.m));

int i;

for(i=0;i<2;i++) c.m[i][i]=1;//定义一个单位矩阵

while(n)

{

if(n & 1)

{

c=mul(c,a);

}

a=mul(a,a);

n=n>>1;

}

return c;

}

int main()

{

long long n,k;

cin>>n>>k;

memset(ans.m,0,sizeof(ans.m));

ans.m[0][0]=4;

ans.m[0][1]=3;

ans.m[1][0]=1;

ans.m[1][1]=0;//这是构建常数矩阵,上面的公式可以参考,主要是其参数

n=n-2;//前俩个冒险者减去

ans=quickpower(ans,n);//求出常数矩阵的n-2次方

memset(res.m,0,sizeof(res.m));

res.m[0][0]=233;

res.m[1][0]=4;

res=mul(ans,res);//求出最后的结果矩阵

k=k-res.m[0][0];

cout<

return 0;

}

以上就是我对矩阵快速幂的整理和理解,希望对大家有所帮助!

相关文章

哈希函数:为什么你的密码存储离不开 SHA-256?

微信文章搜索更高效,高级搜索助你快速找到需要的内容!

dnf天界徽章怎么得到2024(兑换位置、获得方法、用处)

红帽linux命令改中文

移动卡欠费多久会自动销户(移动卡欠费多久会自动销户后又交钱销卡会影响信用)

西安交通大学钱学森班最全解读

《钢铁侠》测试题带答案.pdf

占星骰子怎么玩?记住这3点就够了(实用帖)

后弦为什么不红(后弦的个人简介)