首先推荐matrix67的一篇好文章,《十个利用矩阵乘法解决的经典题目》。讲的非常清晰。
为什么他讲矩阵讲的很清晰呢?因为他叫matrix67。。(大雾
矩阵乘法:Pi,j=ΣAi,k*Bk,j
显而易见 ,矩阵乘法满足结合律但不满足交换律,程序里不要写反了。
矩阵快速幂:因为矩阵乘法满足结合律,所以可以用快速幂加速。复杂度O(n3logK)。
注意通常把矩阵的快速幂写成迭代而不是递归,因为矩阵通常比较占地方,写成迭代比较好。
1 Quickmatrix(martix m,int k){ 2 //注意ans的初始化,或者在第一次使用ans时令ans=m; 3 while (k){ 4 if (k&1) ans*=m; 5 m=m*m; 6 k>>=1; 7 } 8 }
常见应用1:
利用矩阵乘法加速线性递推。因为矩阵本就是描述线性变换的,所以用来表示线性递推就很自然。
例如计算斐波那契数列的第n项,就可以根据斐波那契数列的定义构造一个矩阵,使其能将向量(Fn-2,Fn-1)变换到向量(Fn-1,Fn-2+Fn-1)
显然,我们可以得到,那么第n项就是这个2 x 2的矩阵自乘n次,再乘以(0,1)的结果。
常见应用2:
利用矩阵乘法统计图中的路径方案数。
根据定义,某个图的邻接01矩阵自乘n次后,Ai,j就是从i到j经过n条边的路径方案数。
这个问题可以理解为一般意义上的计数问题。很多统计方案的问题,实质上就是其状态图中的路径方案数问题。
例如文章中的例题9
【例题】SCOI2009 迷路
给出一个有向有权图,问从1到n,长度为T的路径一共有多少条。
注意到题目中每条路径的长度不超过10,那么就可以拆点转化为应用2.
附上代码:
View Code
1 #include <cstdio> 2 #include <cstdlib> 3 #include <algorithm> 4 #include <iostream> 5 #include <cstring> 6 #include <cmath> 7 #include <stack> 8 #include <ctime> 9 #define INF (9999999) 10 #define MAXN (100+10) 11 #define BreakTest //cout<<"Here!"<<endl; 12 using namespace std; 13 /*Gloable*/ 14 int map[MAXN][MAXN]; 15 int newpoint[MAXN][11],np=1; 16 int inside[MAXN]; 17 /*ADT & reload*/ 18 struct matrix{ 19 int p[MAXN][MAXN]; 20 int x,y; 21 matrix(){memset(p,0,sizeof(p));} 22 }m; 23 typedef struct matrix matrix; 24 matrix operator * (matrix a ,matrix b){//a.x==b.y 25 matrix ans; 26 for(int i=1;i<=a.x;i++) 27 for (int j=1;j<=b.y;j++) 28 for (int k=1;k<=a.y;k++) 29 ans.p[i][j]=(((a.p[i][k]%2009)*(b.p[k][j]%2009))%2009+ans.p[i][j]%2009)%2009; 30 ans.x=a.x; 31 ans.y=b.y; 32 return ans; 33 } 34 /*Funciton*/ 35 matrix quickmatrix(matrix m,long long k){ 36 matrix ans; 37 bool exits=false; 38 while (k){ 39 if (k&1==1){ 40 if (!exits) {ans=m;exits=true;} 41 else 42 ans=ans*m; 43 } 44 k>>=1; 45 m=m*m; 46 } 47 return ans; 48 } 49 int main() 50 { 51 int n; 52 long long t; 53 char str[15]; 54 int i,j,k; 55 scanf("%d%lld",&n,&t); 56 for (i=1;i<=n;i++){ 57 scanf("%s",str); 58 for (j=0;str[j];j++){ 59 if (str[j]!='0') 60 map[i][j+1]=str[j]-'0'; 61 else 62 map[i][j+1]=-1; 63 } 64 } 65 #ifdef DEBUG 66 for (i=1;i<=n;i++){ 67 for(j=1;j<=n;j++) 68 cout<<map[i][j]<<" "; 69 cout<<endl; 70 } 71 #endif // DEBUG 72 73 74 75 for (i=1;i<=n;i++){ 76 int maxlen=-INF; 77 for (j=1;j<=n;j++){ 78 if (map[j][i]>maxlen) maxlen=map[j][i]; 79 } 80 81 inside[i]=maxlen-1; 82 for (j=0;j<=inside[i];j++){ 83 newpoint[i][j]=np++; 84 } 85 } 86 87 #ifdef DEBUG 88 for (i=1;i<=n;i++) 89 cout<<inside[i]<<" "; 90 cout<<endl; 91 #endif // DEBUG 92 93 94 95 for (i=1;i<=n;i++){ 96 for (j=1;j<=inside[i];j++){ 97 m.p[newpoint[i][j]][newpoint[i][j-1]]=1; 98 } 99 } 100 for (i=1;i<=n;i++){ 101 for (j=1;j<=n;j++){ 102 if (map[i][j]!=-1){ 103 m.p[newpoint[i][0]][newpoint[j][map[i][j]-1]]=1; 104 } 105 } 106 } 107 108 #ifdef DEBUG 109 cout<<np<<endl; 110 111 for (i=1;i<np;i++){ 112 for(j=1;j<np;j++) 113 cout<<m.p[i][j]<<" "; 114 cout<<endl; 115 } 116 #endif // DEBUG 117 118 119 120 m.x=m.y=np-1; 121 matrix ans=quickmatrix(m,t); 122 printf("%d\n",ans.p[newpoint[1][0]][newpoint[n][0]]); 123 return 0; 124 125 }