转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
做了几个矩阵问题,总结一下。
矩阵是个很神奇的东西,有时候对于一个有规律的操作,需要执行很多次的时候,有时候可以构造矩阵很巧妙的解决。
另外对于递推式求解,可以通过构造矩阵巧妙解决。
经典的便是FIB数列,以及FIB数列的求和问题。
HDU 1575 Tr A
http://acm.hdu.edu.cn/showproblem.php?pid=1575
赤裸的矩阵快速幂乘
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 10
#define inf 1<<29
#define MOD 9973
#define LL long long
using namespace std;
struct Matrix{
int m[N][N];
}init;
int n,k;
Matrix Mult(Matrix m1,Matrix m2){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=(ans.m[i][j]+m1.m[i][k]*m2.m[k][j])%MOD;
}
return ans;
}
Matrix Pow(Matrix m1,int b){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1);
m1=Mult(m1,m1);
b>>=1;
}
return ans;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d",&init.m[i][j]);
init=Pow(init,k);
int ans=0;
for(int i=0;i<n;i++)
ans=(ans+init.m[i][i])%MOD;
printf("%d\n",ans);
}
return 0;
}
HDU 1588 Gauss Fibonacci
http://acm.hdu.edu.cn/showproblem.php?pid=1588
构造矩阵,通过矩阵乘法可以得到FIB数列的某一项,矩阵为{1,1,1,0}
其中这里要求的为
F(b)+F(k+b)+F(2*k+b)……
用矩阵表示即为A^b+A^(k+b)……,可以转化为A^b*(A^(0)+A^(k)……)
将K=A^k,即A^b*(K^0+K^1+K^2……),对于括号内部部分,有经典的二分解法,在Matrix67博客里面也有介绍
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 10
using namespace std;
struct Matrix{
LL m[N][N];
}init,unit;
int MOD;
Matrix Mult(Matrix m1,Matrix m2,int n=2){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=((LL)ans.m[i][j]+m1.m[i][k]*m2.m[k][j])%MOD;
}
return ans;
}
Matrix Pow(Matrix m1,int b,int n=2){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1,n);
m1=Mult(m1,m1,n);
b>>=1;
}
return ans;
}
Matrix Add(Matrix m1,Matrix m2,int n=2){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=((LL)m1.m[i][j]+m2.m[i][j])%MOD;
return ans;
}
Matrix slove(Matrix init,int k,int n=2){
if(k==1)
return init;
Matrix temp=slove(init,k>>1,n);
temp=Add(temp,Mult(temp,Pow(init,k>>1)));
if(k&1)
return Add(temp,Pow(init,k));
else
return temp;
}
int main(){
int k,b,n;
while(scanf("%d%d%d%d",&k,&b,&n,&MOD)!=EOF){
init.m[0][0]=init.m[0][1]=init.m[1][0]=1;
init.m[1][1]=0;
unit.m[0][0]=unit.m[1][1]=1;
unit.m[1][0]=unit.m[0][1]=0;
Matrix t;
t=Pow(init,b);
init=Pow(init,k);
//init.m[0][1]即第k项fib,为A^k
init=Add(unit,slove(init,n-1)); //B=A^k, B^0+B^1+B^2……+B^n-1
init=Mult(init,t);
printf("%I64d\n",init.m[0][1]);
}
return 0;
}
HDU 1757 A Simple Math Problem
http://acm.hdu.edu.cn/showproblem.php?pid=1757
经典的构造矩阵解决递推式问题
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 10
#define inf 1<<29
//#define MOD 9973
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
struct Matrix{
LL m[N][N];
}init,unit;
int MOD;
Matrix Mult(Matrix m1,Matrix m2,int n=10){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=((LL)ans.m[i][j]+m1.m[i][k]*m2.m[k][j])%MOD;
}
return ans;
}
Matrix Pow(Matrix m1,int b,int n=10){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1,n);
m1=Mult(m1,m1,n);
b>>=1;
}
return ans;
}
Matrix Add(Matrix m1,Matrix m2,int n=10){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=((LL)m1.m[i][j]+m2.m[i][j])%MOD;
return ans;
}
Matrix slove(Matrix init,int k,int n=10){
if(k==1)
return init;
Matrix temp=slove(init,k>>1,n);
temp=Add(temp,Mult(temp,Pow(init,k>>1)));
if(k&1)
return Add(temp,Pow(init,k));
else
return temp;
}
void debug(Matrix m1){
for(int i=0;i<10;i++){
for(int j=0;j<10;j++)
printf("%d ",m1.m[i][j]);
printf("\n");
}
}
int main(){
int k,b,n;
int a[10];
while(scanf("%d%d",&k,&MOD)!=EOF){
for(int i=0;i<10;i++)
scanf("%d",&a[i]);
if(k<10)
printf("%d\n",k);
else{
memset(init.m,0,sizeof(init.m));
for(int i=0;i<10;i++)
init.m[i][0]=a[i];
for(int i=1;i<10;i++)
init.m[i-1][i]=1;
init=Pow(init,k-9);
LL ans=0;
for(int i=0;i<10;i++)
ans=(ans+(9-i)*init.m[i][0])%MOD;
printf("%I64d\n",ans);
}
}
return 0;
}
HDU 2157 How many ways??
http://acm.hdu.edu.cn/showproblem.php?pid=2157
又是一个经典的应用 ,在离散数学中有讲,可达矩阵的K次幂便是从i到j走K步能到达的方案数
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 25
#define inf 1<<29
#define MOD 1000
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
struct Matrix{
LL m[N][N];
}init,unit;
Matrix Mult(Matrix m1,Matrix m2,int n=10){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=((LL)ans.m[i][j]+m1.m[i][k]*m2.m[k][j])%MOD;
}
return ans;
}
Matrix Pow(Matrix m1,int b,int n=10){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1,n);
m1=Mult(m1,m1,n);
b>>=1;
}
return ans;
}
Matrix Add(Matrix m1,Matrix m2,int n=10){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=((LL)m1.m[i][j]+m2.m[i][j])%MOD;
return ans;
}
Matrix slove(Matrix init,int k,int n=10){
if(k==1)
return init;
Matrix temp=slove(init,k>>1,n);
temp=Add(temp,Mult(temp,Pow(init,k>>1)));
if(k&1)
return Add(temp,Pow(init,k));
else
return temp;
}
void debug(Matrix m1){
for(int i=0;i<10;i++){
for(int j=0;j<10;j++)
printf("%d ",m1.m[i][j]);
printf("\n");
}
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m)!=EOF&&n+m){
memset(init.m,0,sizeof(init.m));
int u,v,q,k;
while(m--){
scanf("%d%d",&u,&v);
init.m[u][v]=1;
}
scanf("%d",&q);
while(q--){
scanf("%d%d%d",&u,&v,&k);
Matrix unit=Pow(init,k,n);
printf("%d\n",unit.m[u][v]);
}
}
return 0;
}
http://poj.org/problem?id=3233
经典矩阵二分,A^1+A^2+A^3……A^n,如果n为偶数A^1+A^2……A^n/2+A^(n/2)*(A^1+A^2……A^n/2)如果是奇数,就在最后再加一项A^n,这样就可以递归二分下去。
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 35
#define inf 1<<29
//#define MOD 9973
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
struct Matrix{
int m[N][N];
}init,unit;
int MOD;
Matrix Mult(Matrix m1,Matrix m2,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=(ans.m[i][j]+m1.m[i][k]*m2.m[k][j])%MOD;
}
return ans;
}
Matrix Pow(Matrix m1,int b,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1,n);
m1=Mult(m1,m1,n);
b>>=1;
}
return ans;
}
Matrix Add(Matrix m1,Matrix m2,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(m1.m[i][j]+m2.m[i][j])%MOD;
return ans;
}
Matrix slove(Matrix init,int k,int n){
if(k==1)
return init;
Matrix temp=slove(init,k>>1,n);
temp=Add(temp,Mult(temp,Pow(init,k>>1,n),n),n);
if(k&1)
return Add(temp,Pow(init,k,n),n);
else
return temp;
}
void debug(Matrix m1,int n){
for(int i=0;i<n;i++){
printf("%d",m1.m[i][0]);
for(int j=1;j<n;j++)
printf(" %d",m1.m[i][j]);
printf("\n");
}
}
int main(){
int k,b,n;
while(scanf("%d%d%d",&n,&k,&MOD)!=EOF){
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
scanf("%d",&init.m[i][j]);
init.m[i][j]%=MOD;
}
debug(slove(init,k,n),n);
}
return 0;
}
ZOJ 3497 Mistwald
同样首先判断是否可达,如果K次不可达,则必然是False。如果K次只能到达目标点,则说明是实话,如果K次有多点可达,则说明是可能
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3497
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 30
#define inf 1<<29
//#define MOD 9973
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
struct Matrix{
int m[N][N];
}init,unit;
Matrix Mult(Matrix m1,Matrix m2,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=(ans.m[i][j]+m1.m[i][k]*m2.m[k][j]);
}
return ans;
}
Matrix Pow(Matrix m1,int b,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1,n);
m1=Mult(m1,m1,n);
b>>=1;
}
return ans;
}
Matrix Add(Matrix m1,Matrix m2,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(m1.m[i][j]+m2.m[i][j]);
return ans;
}
int main(){
int t,c,r;
scanf("%d",&t);
while(t--){
scanf("%d%d",&r,&c);
memset(init.m,0,sizeof(init.m));
for(int i=0;i<r;i++){
for(int j=0;j<c;j++){
int x1,x2,x3,x4,y1,y2,y3,y4;
getchar();
scanf("((%d,%d),(%d,%d),(%d,%d),(%d,%d))",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
if(i==r-1&&j==c-1) continue;
init.m[i*c+j][(x1-1)*c+y1-1]=1;
init.m[i*c+j][(x2-1)*c+y2-1]=1;
init.m[i*c+j][(x3-1)*c+y3-1]=1;
init.m[i*c+j][(x4-1)*c+y4-1]=1;
}
}
int q,k;
// for(int i=0;i<r*c;i++)
// init.m[i][i]=0;
scanf("%d",&q);
while(q--){
scanf("%d",&k);
Matrix tmp=Pow(init,k,r*c);
if(tmp.m[0][r*c-1]==0){
puts("False");
continue;
}
int cnt=0;
for(int i=0;i<r*c-1;i++)
if(tmp.m[0][i])
cnt++;
if(!cnt)
puts("True");
else
puts("Maybe");
}
puts("");
}
return 0;
}
HDU 2807 The Shortest Path
http://acm.hdu.edu.cn/showproblem.php?pid=2807
没啥好说的,直接搞就行了。不过挺卡时间的,注意优化
#include <cstdio>
#include <iostream>
#define NN 81
#define inf 1<<29
using namespace std;
int n,m;
int matrix[NN][NN][NN];
int dis[NN][NN];
void init(){
for(int i=1;i<=n;i++)
for (int j=1; j<=m; j++)
for (int k=1; k<=m; k++)
scanf("%d",&matrix[i][j][k]);
}
void get_dis(){
int temp[NN][NN];
for (int a=1; a<=n; a++)
for (int b=1; b<=n; b++)
dis[a][b]=inf;
for (int a=1; a<=n; a++)
for (int b=1; b<=n; b++) {
if(a==b) continue;
for (int i=1; i<=m; i++){
for (int j=1; j<=m; j++){
temp[i][j]=0;
for (int k=1; k<=m; k++)
temp[i][j]+=matrix[a][i][k]*matrix[b][k][j];
}
}
for(int c=1; c<=n; c++){
if(a==c||b==c) continue;
int flag=1;
for (int i=1; i<=m && flag; i++)
for (int j=1; j<=m && flag; j++)
if (temp[i][j]!=matrix[c][i][j]) flag=0;
if (flag) dis[a][c]=1;
}
}
}
void Floyed(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if (k==i || k==j || i==j) continue;
if (dis[i][j]>dis[i][k]+dis[k][j])
dis[i][j]=dis[i][k]+dis[k][j];
}
}
void Query(){
int t,x,y;
scanf("%d",&t);
while(t--){
scanf("%d%d",&x,&y);
if (dis[x][y]>=inf)
printf("Sorry\n");
else
printf("%d\n",dis[x][y]);
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF&&n!=0&&m!=0){
init();
get_dis();
Floyed();
Query();
}
return 0;
}
HDU 3483 A Very Simple Problem
http://acm.hdu.edu.cn/showproblem.php?pid=3483
贴个图,神构造,矩阵完美解决
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 55
#define inf 1<<29
//#define MOD 9973
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
struct Matrix{
LL m[N][N];
}init,unit;
LL MOD;
Matrix Mult(Matrix m1,Matrix m2,int n){
Matrix ans;
memset(ans.m,0,sizeof(ans.m));
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
if(m1.m[i][k])
for(int j=0;j<n;j++){
ans.m[i][j]+=m1.m[i][k]*m2.m[k][j];
if(ans.m[i][j]>=MOD)ans.m[i][j]%=MOD;
}
/*for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=(ans.m[i][j]+m1.m[i][k]*m2.m[k][j])%MOD;
}*/
return ans;
}
Matrix Pow(Matrix m1,int b,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1,n);
m1=Mult(m1,m1,n);
b>>=1;
}
return ans;
}
Matrix Add(Matrix m1,Matrix m2,int n){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(m1.m[i][j]+m2.m[i][j])%MOD;
return ans;
}
int n,x;
LL c[N][N];
int main(){
while(scanf("%d%d%d",&n,&x,&MOD)!=EOF){
if(n==-1&&x==-1&&MOD==-1) break;
memset(init.m,0,sizeof(init.m));
for(int i=0;i<=x;i++){
c[i][0]=1;c[i][i]=1;
for(int j=1;j<i;j++){
c[i][j]=(c[i-1][j]+c[i-1][j-1]);
if(c[i][j]>=MOD)
c[i][j]-=MOD;
}
}
for(int j=0;j<=x;j++)
for(int i=0;i<=j;i++)
init.m[i][j]=(c[j][i]*x)%MOD;
for(int i=0;i<=x;i++)
init.m[i][x+1]=(x*c[x][i])%MOD;
init.m[x+1][x+1]=1;
init=Pow(init,n-1,x+2);
LL ans=0;
for(int i=0;i<=x+1;i++)
ans=(ans+(LL)x*init.m[i][x+1])%MOD;
printf("%I64d\n",ans);
}
return 0;
}
HDU 2276 Kiki & Little Kiki 2
每一个位置的状态ai=(ai+ai-1)%2,可以用异或加速
构造矩阵,便可解决
1 1 0 0 0 0 0
0 1 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 1 1 0 0
0 0 0 0 1 1 0
0 0 0 0 0 1 1
1 0 0 0 0 0 1
http://acm.hdu.edu.cn/showproblem.php?pid=2276
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 105
#define inf 1<<29
#define MOD 9973
#define Max 301
#define LL long long
#define eps 1e-7
#define zero(a) fabs(a)<eps
#define equal(a,b) zero(a-b)
using namespace std;
struct Matrix{
int m[N][N];
}init,unit;
int n,k;
Matrix Mult(Matrix m1,Matrix m2){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
ans.m[i][j]=0;
for(int k=0;k<n;k++)
ans.m[i][j]=(ans.m[i][j]+(m1.m[i][k]*m2.m[k][j]))%2;
}
return ans;
}
Matrix Pow(Matrix m1,int b){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1);
m1=Mult(m1,m1);
b>>=1;
}
return ans;
}
void debug(Matrix m1){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
printf("%d ",m1.m[i][j]);
printf("\n");
}
}
char str[N];
int main(){
while(scanf("%d",&k)!=EOF){
scanf("%s",str);
n=strlen(str);
memset(init.m,0,sizeof(init.m));
for(int i=0;i<n;i++)
init.m[i][i]=init.m[(i-1+n)%n][i]=1;
init=Pow(init,k);
//debug(init);
for(int i=0;i<n;i++){
int t=0;
for(int j=0;j<n;j++)
t=t^((str[j]-'0')*init.m[j][i]);
printf("%d",t);
}
puts("");
}
return 0;
}
HDU 2855 Fibonacci Check-up
http://acm.hdu.edu.cn/showproblem.php?pid=2855
这个完全就是神构造,完全想不到,或者可以通过打表,打规律得到
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 2
using namespace std;
struct Matrix{
int m[N][N];
}init,unit;
int n=2;
int MOD;
Matrix Mult(Matrix m1,Matrix m2){
Matrix ans;
memset(ans.m,0,sizeof(ans.m));
for(int i=0;i<n;i++)
for(int k=0;k<n;k++){
if(m1.m[i][k])
for(int j=0;j<n;j++)
ans.m[i][j]=(ans.m[i][j]+(m1.m[i][k]*m2.m[k][j]))%MOD;
}
return ans;
}
Matrix Pow(Matrix m1,int b){
Matrix ans;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ans.m[i][j]=(i==j);
while(b){
if(b&1)
ans=Mult(ans,m1);
m1=Mult(m1,m1);
b>>=1;
}
return ans;
}
int main(){
int t,k;
scanf("%d",&t);
while(t--){
scanf("%d%d",&k,&MOD);
if(k==0){
printf("0\n");
continue;
}
init.m[0][0]=init.m[0][1]=init.m[1][0]=1;
init.m[1][1]=0;
init=Pow(init,2*k-1);
printf("%d\n",init.m[0][0]);
}
return 0;
}