矩阵乘法
矩阵乘法公式:
模板(LOJ100):
#include <bits/stdc++.h>
using namespace std;
const int Max=501;
const int mod=1000000007;
int n,m,p;
int a[Max][Max],b[Max][Max],c[Max][Max];
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') {f=-1;c=getchar();}
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
int main()
{
n=get_int(),p=get_int(),m=get_int();
for(int i=1;i<=n;i++)
for(int j=1;j<=p;j++) a[i][j]=get_int();
for(int i=1;i<=p;i++)
for(int j=1;j<=m;j++) b[i][j]=get_int();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=p;k++)
c[i][j] = (c[i][j] + (long long)a[i][k] * b[k][j]) % mod;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++) cout<<(c[i][j] % mod +mod) % mod<<" ";
cout<<"\n";
}
return 0;
}
一.斐波拉契系列问题
1.POJ3070
解析:
大概意思就是求Fibonacci数列第N项。
建一个2*2的矩阵A:
0 1
1 1
然后把我们每次存的两个数放在另一个矩阵B里面:
f[ n - 1 ] f[ n ]
那么把这两个矩阵相乘就可以得到另一个矩阵:
f[ n ] f[ n + 1 ]
所以初始化矩阵{f[ 0 ],f[ 1 ]},第N项即为矩阵A的N次方乘以初始矩阵,用矩阵快速幂实现。
代码:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
using namespace std;
const int mod=10000;
int n;
inline void mul(int a[2][2],int f[2])
{
int c[2];
memset(c,0,sizeof(c));
for(int i=0;i<2;i++)
for(int k=0;k<2;k++)
c[i] = (c[i] + (long long)a[k][i] * f[k]) % mod;
memcpy(f,c,sizeof(c));
}
void mulself(int a[2][2]) {
int c[2][2];
memset(c, 0, sizeof(c));
for (int i = 0; i < 2; i++)
for (int j = 0; j < 2; j++)
for (int k = 0; k < 2; k++)
c[i][j] = (c[i][j] + (long long)a[i][k] * a[k][j]) % mod;
memcpy(a, c, sizeof(c));
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==-1) break;
int a[2][2] = {{0,1},{1,1}},f[2]={0,1};
while(n)
{
if(n&1) mul(a,f);
n>>=1;
mulself(a);
}
cout<<f[0]<<"\n";
}
return 0;
}
2.LOJ10221
解析:
跟上一道题的思路相似,构造矩阵A:
1 0 0
1 1 1
0 1 0
再建一个矩阵B:
s[ n - 1 ] f[ n ] f[ n - 1 ]。
那么把这两个矩阵相乘就可以得到另一个矩阵:
s[ n ] f[ n + 1 ] f[ n ]。
然后矩阵快速幂。
代码:
#include <bits/stdc++.h>
using namespace std;
int n,m;
int a[3][3] = {{1,0,0},{1,1,1},{0,1,0}},b[3]={1,1,1};
inline int get_int()
{
int x=0,f=1;
char c;
for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
if(c=='-') {f=-1;c=getchar();}
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void mul()
{
int c[3];
memset(c,0,sizeof(c));
for(int j=0;j<3;j++)
for(int k=0;k<3;k++) c[j] = (c[j] + (long long)b[k] * a[k][j]) % m;
memcpy(b,c,sizeof(c));
}
inline void mulself()
{
int c[3][3];
memset(c,0,sizeof(c));
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++) c[i][j] =(c[i][j] + (long long)a[i][k] * a[k][j]) % m;
memcpy(a,c,sizeof(c));
}
int main()
{
n=get_int(),m=get_int();
n--;
while(n)
{
if(n&1) mul();
n>>=1;
mulself();
}
cout<<b[0]<<"\n";
return 0;
}
二.综合应用
1.BZOJ1009
2.BZOJ1297
总结:
矩阵乘法一大特点就是能加速递推,再log级别的复杂度内解决问题,常用于递推与DP,其难点在于构造出矩阵。