一个矩阵就是一个二维数组,为了方便声明多个矩阵,我们一般会将矩阵封装一个类或定义一个矩阵的结构体,我采用的是后者:
struct Mat
{
int mat[Max][Max];
}
最特殊的矩阵应该就是单位矩阵E了,它的对角线的元素为1,非对角线元素为0。
一般矩阵乘法采用朴素的O(n^3)的算法:
Mat operator*(Mat a,Mat b)在ACM的题目中,我们一般考虑的是n阶方阵之间的乘法以及n阶方阵与n维向量(把向量看成n×1的矩阵)的乘法。矩阵乘法最重要的性质就是满足结合律,同时它另一个很重要的性质就是不满足交换率,这保证了矩阵的幂运算满足快速幂取模(A^x % MOD)算法:
假设k = 27,则k的二进制表示为11011,所以
,可以看出:k的二进制的每一位矩阵A都要平方,在k二进制为1的位:末矩阵×平方后的A,在k二进制为0的位则末矩阵×E(单位矩阵),即不变。代码如下:
许多题目还要求S = A + A2 + A3 + … +Ak.。其实再作一次二分即可:只需计算log(n)个A的幂即可。
Mat solve(Mat a,int p)
{
if(p==1)
return a;
/*如果p为奇数,则对p-1进行二分,a^p+二分结果*/
/*
A^1+A^2+A^3+A^4+A^5+A^6+A^7 = (A^1+A^2+A^3)+ A^3*(A^1+A^2+A^3)+A^7=A^7+solve(A,p-1)
*/
else if(p&1)
return (a^p)+solve(a,p-1);
/*p为偶数,则直接二分*/
/*
A^1+A^2+A^3+A^4+A^5+A^6 = (A^1+A^2+A^3)+ A^3*(A^1+A^2+A^3) = (A^3+e)*(A^1+A^2+A^3)
推广即可得到当p为偶数时 A^1+A^2+A^3+……+A^p = (A^(p/2)+e) * solve(A,p/2);
*/
else
return ((a^(p>>1))+e)*solve(a,p>>1);
}
hdu 1757
10 9999 1 1 1 1 1 1 1 1 1 1 20 500 1 0 1 0 1 0 1 0 1 0
45 104
#include<stdio.h> #include<string.h> struct haha { int mar[10][10]; }a,b,c; int n,m; struct haha multi(struct haha a1,struct haha a2) { struct haha temp; int i,j,k; for(i=0;i<10;i++) for(j=0;j<10;j++) { temp.mar[i][j]=0; for(k=0;k<10;k++) { temp.mar[i][j]+=(a1.mar[i][k]*a2.mar[k][j])%m; } temp.mar[i][j]%=m; } return temp; } struct haha bin(int cnt)//二分思想 下面有更精简的方法 { struct haha tmp; if(cnt==1) return a; if(cnt%2==0) { tmp=bin(cnt/2); return multi(tmp,tmp); } else { tmp=bin((cnt-1)/2); tmp=multi(tmp,tmp);return multi(tmp,a); } } /*void matrix_binary()//二分思想也可以用二进制方法解决 { while(k) { if(k & 1) //与1计算后可以得到二进制最后一位是否为1,为1就乘,不是就不乘 b = matrixmul(b,a);//注意 b的初始为E单位矩阵 a = matrixmul(a,a); k = k >> 1; } } //上面原理解释: 假设k的二进制是10111 即为23 矩阵要乘23次 a始终用来记录2 4 8 16....... 当k=10111 b变成了a a为2次矩阵相乘 当k=1011 b=b*a 为3次矩阵相乘 a变成了4次相乘 k=101 b为7次 a为8次 k=10 b为7次 a为16次 k=1 b为23 a=32 k=0 退出 那么这时候b就是我们得到的矩阵相乘结果23次 */ int main() { int i,j,ans; while(scanf("%d %d",&n,&m)!=EOF) { // for(i=0;i<10;i++) // for(j=0;j<10;j++) // { // if(i==j-1) a.mar[i][j-1]=1;//搞了整整一天没想到居然是在这里犯的错误啊 矩阵的初始化搞错了 // else a.mar[i][j]=0; // } memset(a.mar,0,sizeof(a.mar)); for(i = 1;i < 10;i++) a.mar[i][i-1] = 1; for(j=0;j<10;j++) scanf("%d",&a.mar[0][j]); if(n<10) {printf("%d\n",n);continue;} n=n-9; c=bin(n); ans=0; for(i = 0;i < 10;i++) ans += (c.mar[0][i] * (9-i)) % m; printf("%d\n",ans%m); } return 0; }
参考内容来自http://blog.csdn.net/q3498233/article/details/5786180
矩阵乘法大神解题报告http://www.cppblog.com/notonlysuccess/archive/2009/03/03/75405.aspx
矩阵乘法题目整理