矩阵乘法的应用(hdu1575,hdu1588,poj3070,poj3233,poj3613)

首先感叹下矩阵的强大,真心强大!

然后推荐下 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;
}


hdu1588 Gauss Fibonacci

这个题有点意思,我是没想到怎么处理,这里有篇给力的文章:

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;
}


poj3070 Fibonacci

最简单的,有人说过是雅礼下至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;
}


poj3233 Matrix Power Series

矩阵的等比数列和,这个用二分实现,表示很经典,很强大,代码不是自己的,贴来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;
}

poj3613 Cow Relays

求图中从一个点到另一个点恰好经过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;
}



你可能感兴趣的:(c,struct,IO,ini,Matrix)