首先感叹下矩阵的强大,真心强大!
然后推荐下 Matrix67 大神的神作:十个利用矩阵乘法解决的经典题目
大神说的很明白了,我觉得再说啥都多余了,请直接去大神那里看吧,我只是刷了几道简单的入门题,贴下代码,和大家交流下:
hdu1575 Tr A
矩阵乘法 + 快速幂,很简单
代码:
#include<cstdio> const int mod = 9973; const int N = 11; int n; struct prog{ int a[N][N],i,j; void init(){ for(i=0;i<N;i++){ for(j=0;j<N;j++){ if(i==j) a[i][j]=1; else a[i][j]=0; } } } }; prog matrixmult(prog a,prog b){ int i,j,k; prog c; for(i=0;i<n;i++){ for(j=0;j<n;j++){ c.a[i][j]=0; for(k=0;k<n;k++) c.a[i][j]+=((a.a[i][k]*b.a[k][j])%mod); c.a[i][j]%=mod; } } return c; } prog mult(prog s,int k){ prog ans; ans.init(); while(k>=1){ if(k&1)ans=matrixmult(ans,s); k=k>>1; s=matrixmult(s,s); } return ans; } int main() { int i,j,k,cases; prog s; scanf("%d",&cases); while(cases--) { scanf("%d%d",&n,&k); for(i=0;i<n;i++){ for(j=0;j<n;j++)scanf("%d",&s.a[i][j]); } s=mult(s,k); int sum=0; for(i=0;i<n;i++) sum+=s.a[i][i]; printf("%d\n",sum%mod); } return 0; }
这个题有点意思,我是没想到怎么处理,这里有篇给力的文章:
http://www.cnblogs.com/Knuth/archive/2009/09/04/1559951.html
他给了两个思路,亚伟用第一个方法过的(代码在这),我用的第二个方法:
/* A^b*( I + A^k + (A^k)^2 + .... + (A^k)^(N-1) ) 设A^k=B 我们来设置这样一个矩阵 B I O I 其中O是零矩阵,I是单位矩阵 将它乘方,得到 B^2 I+B O I 乘三方,得到 B^3 I+B+B^2 O I 乘四方,得到 B^4 I+B+B^2+B^3 O I 既然已经转换成矩阵的幂了,继续用我们的二分或者二进制法,直接求出幂就可以了 */ #include<cstdio> #include<cstring> #define INT __int64 struct prog{ INT a[2][2]; void init(){ a[0][0]=a[0][1]=a[1][0]=1; a[1][1]=0; } /* 斐波那契矩阵 1,1 1,0 */ void Print(){//打印输出,方便检查 puts("***********************"); for(int i=0;i<2;i++){ for(int j=0;j<2;j++)printf("%d ",a[i][j]); puts(""); }puts("***********************"); } }; struct prog_x{//四位构造矩阵 INT a[4][4]; void init(){ memset(a,0,sizeof(a)); a[0][2]=a[1][3]=a[2][2]=a[3][3]=1; } /* 0,0,1,0 0,0,0,1 0,0,1,0 0,0,0,1 */ void Print(){//打印输出,方便检查 puts("***********************"); for(int i=0;i<4;i++){ for(int j=0;j<4;j++)printf("%d ",a[i][j]); puts(""); }puts("***********************"); } }; int mod; prog matrixmult(prog a,prog b){ int i,j,k; prog c; for(i=0;i<2;i++){ for(j=0;j<2;j++){ c.a[i][j]=0; for(k=0;k<2;k++) c.a[i][j]+=((a.a[i][k]*b.a[k][j])%mod); c.a[i][j]%=mod; } } return c; } prog mult(prog s,int k){ prog ans; ans.init(); while(k>=1){ if(k&1)ans=matrixmult(ans,s); k=k>>1; s=matrixmult(s,s); } return ans; } prog_x matrixmult_x(prog_x a,prog_x b){ int i,j,k; prog_x c; for(i=0;i<4;i++){ for(j=0;j<4;j++){ c.a[i][j]=0; for(k=0;k<4;k++) c.a[i][j]+=((a.a[i][k]*b.a[k][j])%mod); c.a[i][j]%=mod; } } return c; } prog_x mult_x(prog_x s,int k){ prog_x ans; int i,j; for(i=0;i<4;i++){ for(j=0;j<4;j++)ans.a[i][j]=s.a[i][j]; } while(k>0){ if(k&1)ans=matrixmult_x(ans,s); k=k>>1; s=matrixmult_x(s,s); } return ans; } int main() { int k,b,n; while(~scanf("%d%d%d%d",&k,&b,&n,&mod)) { prog B,tmp; B.init(); B=mult(B,k-1); //B=A^k /*tmp=A^b,当b==0的时候,tmp=E*/ if(b==0){ tmp.a[0][0]=tmp.a[1][1]=1; tmp.a[0][1]=tmp.a[1][0]=0; } else{ tmp.init(); tmp=mult(tmp,b-1); } prog_x s_x; s_x.init(); s_x.a[0][0]=B.a[0][0]; //将B=A^k填充进构造矩阵的左上角 s_x.a[0][1]=B.a[0][1]; s_x.a[1][0]=B.a[1][0]; s_x.a[1][1]=B.a[1][1]; //s_x.Print(); s_x=mult_x(s_x,n-1); prog ans; //取出右上角的2*2的部分 ans.a[0][0]=s_x.a[0][2]; ans.a[0][1]=s_x.a[0][3]; ans.a[1][0]=s_x.a[1][2]; ans.a[1][1]=s_x.a[1][3]; ans=matrixmult(ans,tmp); printf("%d\n",ans.a[0][1]%mod); } return 0; }
最简单的,有人说过是雅礼下至3岁幼童都会的一道题,= =!
#include<cstdio> struct prog{ int a[2][2]; void init(){ a[1][1]=a[0][1]=a[1][0]=1; a[0][0]=0; } }; prog matrixmul(prog a,prog b){ int i,j,k; prog c; for(i=0;i<2;i++){ for(j=0;j<2;j++){ c.a[i][j]=0; for(k=0;k<2;k++) c.a[i][j]+=(a.a[i][k]*b.a[k][j]); c.a[i][j]%=10000; } } return c; } prog mul(prog s,int k){ prog ans; ans.init(); while(k>=1){ if(k&1)ans=matrixmul(ans,s); k=k>>1; s=matrixmul(s,s); } return ans; } int main() { int n; while(scanf("%d",&n),n!=-1){ if(!n){ printf("0\n");continue; } prog s; s.init(); s=mul(s,n-1); printf("%d\n",s.a[0][1]%10000); } return 0; }
矩阵的等比数列和,这个用二分实现,表示很经典,很强大,代码不是自己的,贴来Ym,理解:
/* 递归求解 K为偶数的时候不需要计算大括号里面的那一项 S_(K) = A+A^2+A^3+...+A^K = (1+A^(K/2)) * (A+A^2+A^3+...+A^(K/2)) + {A^K} = (1+A^(K/2)) * (S_(K/2)) */ #include<cstdio> const int N = 30; int n,mod; struct prog{ int a[N][N],i,j; void init(){ for(i=0;i<N;i++){ for(j=0;j<N;j++){ if(i==j) a[i][j]=1; else a[i][j]=0; } } } }; prog matrixmult(prog a,prog b){ int i,j,k; prog c; for(i=0;i<n;i++){ for(j=0;j<n;j++){ c.a[i][j]=0; for(k=0;k<n;k++) c.a[i][j]+=((a.a[i][k]*b.a[k][j])%mod); c.a[i][j]%=mod; } } return c; } prog mult(prog s,int k){ prog ans; ans.init(); while(k>=1){ if(k&1)ans=matrixmult(ans,s); k=k>>1; s=matrixmult(s,s); } return ans; } prog matriplus(prog a,prog b){ int i,j; for(i=0;i<n;i++){ for(j=0;j<n;j++){ a.a[i][j]+=b.a[i][j]; a.a[i][j]%=mod; } } return a; } prog dfs(prog s,int k){ if(k==1)return s; prog tmp; tmp.init(); //tmp=1 tmp=matriplus(tmp,mult(s,k>>1)); //tmp = 1+A^(k/2) tmp=matrixmult(tmp,dfs(s,k>>1)); //tmp = ( 1+A^(k/2) )*( A+A^2+A^3+...+A^(K/2) ) if(k&1) tmp=matriplus(tmp,mult(s,k));//奇,偶判断 return tmp; } int main() { int i,j,k; prog s; scanf("%d%d%d",&n,&k,&mod); for(i=0;i<n;i++){ for(j=0;j<n;j++) scanf("%d",&s.a[i][j]); } s=dfs(s,k); for(i=0;i<n;i++){ printf("%d",s.a[i][0]); for(j=1;j<n;j++){ printf(" %d",s.a[i][j]); }puts(""); } return 0; }
求图中从一个点到另一个点恰好经过K条边的最短路径的权值和
这个题需要改下 矩阵乘法 以及 矩阵快速幂 的函数,把矩阵乘法里面的乘改成类似 floyd 的松弛(因为求的是最短路径权值和),还有要注意的是,这个题的矩阵规模较大,离散处理后也有 200*200 ,所以这个矩阵是不能定义在结构体内部的,用全局变量好了,我就是这么干的。
代码:
#include<cstdio> #include<cstring> #include<climits> #define min(a,b) ((a)<(b))?(a):(b) const int N = 205; const int INF = 1000000100; int m,p[1001]; int ans[N][N]; void matrixmult(int a[N][N],int b[N][N]){ int i,j,k; int c[N][N]; for(i=0;i<m;i++){ for(j=0;j<m;j++){ c[i][j]=INF; for(k=0;k<m;k++) c[i][j]=min( a[i][k]+b[k][j] , c[i][j] ); } } for(i=0;i<m;i++){ for(j=0;j<m;j++)a[i][j]=c[i][j]; } } void mult(int s[N][N],int k){ int i,j; for(i=0;i<m;i++){ for(j=0;j<m;j++) ans[i][j]=s[i][j]; } k--; while(k>0){ if(k&1) matrixmult(ans,s); k=k>>1; matrixmult(s,s); } } int main() { int mat[N][N]; int i,j,n,t,s,e,from,to,val; while(~scanf("%d%d%d%d",&n,&t,&s,&e)) { for(i=0;i<N;i++){ for(j=0;j<N;j++)mat[i][j]=INF; } memset(p,-1,sizeof(p)); m=0; for(i=0;i<t;i++){ scanf("%d%d%d",&val,&from,&to); if(p[from]<0) p[from] = m++; if(p[to]<0) p[to] = m++; if(val<mat[ p[from] ][ p[to] ]) mat[ p[from] ][ p[to] ] = mat[ p[to] ][ p[from] ] = val; } s=p[s]; e=p[e]; mult(mat,n); printf("%d\n",ans[s][e]); } return 0; }