二:矩阵快速幂
改编自:地址
第一篇介绍了如何快速求幂,这一篇介绍如何用数字快速求幂的思想,来快速求矩阵之幂
这是求矩阵A、B乘积的代码:
const int N=100; int c[N][N]; void multi(int a[][N],int b[][N],int n) { memset(c,0,sizeof c); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) c[i][j]+=a[i][k]*b[k][j]; }
这里我直接写的是n*n的矩阵(即方阵),显然两个相乘是要一行和一列对应乘,那么矩阵乘法是需要A的行数与B的列数相等的(这是A*B的前提条件,可见矩阵的乘法是不满足交换律的)。然而这些一般都是没什么用的,矩阵快速幂只会用到方阵(除非题目是裸的矩阵乘法)。矩阵快速幂都是方阵也就避免的相乘的前提条件,可以放心用。
OK,现在可以求两个矩阵之积,那么矩阵的“平方”和“幂”也就可以求,下面就是矩阵如何快速求幂,和第一篇的思想相同
需要用到一个小知识就是:单位矩阵与矩阵A相乘,结果仍是矩阵A
const int N=10; int tmp[N][N]; void multi(int a[][N],int b[][N],int n) { memset(tmp,0,sizeof tmp); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) for(int k=1;k<=n;k++) tmp[i][j]+=a[i][k]*b[k][j]; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) a[i][j]=tmp[i][j]; } int res[N][N]; void Pow(int a[][N],int n) { memset(res,0,sizeof res); for(int i=1;i<=n;i++) res[i][i]=1; while(n) { if(n&1) multi(res,a,n);//res=res*a;复制直接在multi里面实现了; multi(a,a,n);//a=a*a n>>=1; } }
如上,在最后结果存在res里,如果觉得不爽也可以在pow函数的最后加一个复制,把res复制给a
将n次矩阵相乘减少到logn次,这就是矩阵快速幂的核心妙处
通过将其他问题转化为“求矩阵之幂”,进而运用快速幂的思想求出结果
那么,你会问,怎么会有求“矩阵之幂“这种无聊的问题呀?嘿,还真有
前两篇是基础,第三篇开始实例
据知后事如何,请看下回分解
柳暗花明又一村