参照:http://www.cnblogs.com/yan-boy/archive/2012/11/29/2795294.html
对A^n,我们一般通过连乘(n-1)次,但是我们利用矩阵乘法的结合律做一下简单的改进就能减少连乘的次数,例如,A*A*A*A*A*A => (A*A)*(A*A)*(A*A),可使得连乘次数由5次减少为3次,那么究竟如何利用结合律可以得到最小的连乘次数呢?
答案是:二进制和二分思想的结合
例如,A^21 => (A^16)*(A^4)*(A^1)(21=2^4+2^2+2^0),A^16又可以二分为(A^8)*(A^8),A^8=(A^4)*(A^4)....
从而可将因子数由n降到log(n)
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define N 100 #define ll long long struct Mat{ ll mat[N][N]; }; void showmat(Mat a) { for(int i=0;i<3;i++) { for(int j=0;j<3;j++) printf("%lld ",a.mat[i][j]); printf("\n"); } } void Init(Mat &b)//初始化为单位矩阵 ,要引用 { int i, j, k; for(i = 0; i < 3; ++i) { for(j = 0; j < 3; ++j) { b.mat[i][j] = (i == j);//简略的写法 } } } Mat MatMul(Mat a,Mat b) { Mat c; memset(c.mat, 0, sizeof(c.mat)); int i, j, k; for(i = 0; i < 3; ++i) { for(j = 0; j < 3; ++j) { for(k = 0; k < 3; ++k) { c.mat[i][j] += a.mat[i][k] * b.mat[k][j]; } } } return c; } Mat MATLAB(Mat a,int n)//核心代码,例A^156=(A^4)*(A^8)*(A^16)*(A^128) { Mat b; Init(b); while(n) { if(n&1) b = MatMul(b,a); n >>= 1;//右移 a = MatMul(a,a); } return b; } int main() { int n; Mat a,b; scanf("%d",&n); memset(a.mat,0,sizeof(a.mat)); memset(b.mat,0,sizeof(b.mat)); //生成三维随机矩阵 srand(time(0));//随机种子---stdlib.h for(int i=0;i<3;i++) for(int j=0;j<3;j++) a.mat[i][j] = rand()%100; printf("随机矩阵为:\n"); showmat(a); b = MATLAB(a,n); printf("%d次幂所得结果矩阵为:\n",n); showmat(b); return 0; }
原文:http://www.cnblogs.com/520xiuge/p/5294132.html