poj3725 - Training little cats

133 篇文章 0 订阅

                                   想看更多的解题报告: http://blog.csdn.net/wangjian8006/article/details/7870410
                                     转载请注明出处:
http://blog.csdn.net/wangjian8006

题目大意:让一只猫咪去做训练,在此之前任何猫咪没有花生:
g i:让第i只小猫拿到一颗花生
e i:让第i只小猫吃掉它所拥有的所有花生
s i j:让第i只小猫与第j只小猫交换它们的花生
所有的猫咪执行这一系列的举措并且必须重复m次!你必须确定最后每只小猫拥有的花生的数量。

解题思路:
我们把刚才那3只猫看做一个矩阵{a,b,c},分别代表他们有的花生个数,显然初始是{0,0,0}

当进行s操作的时候,我们将初始矩阵乘上一个矩阵,得到的那个矩阵最好也是1行3列的。
那肯定我们要构造的那个矩阵式3*3的矩阵

s 1 2交换操作就是{a,b,c}*x={b,a,c}

x={0 1 0}

     1 0 0

       0 0 1

那么S操作就是这样的,首先将X看做一个单位矩阵,要交换哪两个,只需要交换他们的列就可以了

对于e操作近似于s操作,将e 2举例:{a,b,c}*x={a,0,c}

x={1 0 0}

      0 0 0

      0 0 1

即将某列置于0

现在问题来了,怎么构造g操作的矩阵。使下面这个等式成立
 g 1操作  {a,b,c}*X={a+1,b,c}
 g 2操作  {a,b,c}*X={a,b+1,c}
 g 3操作  {a,b,c}*X={a,b,c+1}

这样所构造的矩阵会含有a,b,c的值,不可能将构造一个这样的矩阵,这不科学,因为在前面构造s操作与e操作时,我们并不需要知道a,b,c的值

那这样,我们不妨再{a,b,c}矩阵多加一个1,这样我们就能实现我们的+1操作了
  要使g 1操作实现{a,b,c,1}*x={a+1,b,c,1}

那么x= 1 0 0 0

             0 1 0 0

             0 0 1 0

             1 0 0 1

当然这样构造矩阵,这样并不影响我们前面的s与e操作

这样一系列操作之后:

 

而重复m次那么多操作,只是需要将{0,0,0,1}* X^m={a,b,c,1}
这个时候a,b,c就是我们要的答案,构造X次方只能用模拟去构造,因为操作最多只有100次,所有不费什么时间,现在重要的是X^m

我们知道X^m,除了注意一下大数据之外,可以用快速幂解决,但是在数据里面,就算用快速幂求解也会在1s以上的,当然不是说快速幂有问题,而是在矩阵的乘法需要改进。

在实际数据中,其实很多矩阵构造出来是一个很大的100*100的矩阵,但是在矩阵的元素里面有许多0,我们称之为稀疏矩阵。对于稀疏矩阵的乘法,在普通的0(N^3)的矩阵乘法是可以改进的。

 

/*
Memory 816K
Time  157MS
*/
#include <iostream>
using namespace std;
#define MAXV 102

typedef struct{
	int c,r;
	__int64 mat[MAXV][MAXV];
}Matrix;

Matrix ans,cnt;
__int64 n,m,k;

void Input(){			//构造矩阵
	char c;
	int i,t,j;
	__int64 w,v;
	cnt.r=cnt.c=n+1;
	memset(cnt.mat,0,sizeof(cnt.mat));
	for(i=0;i<cnt.r;i++) cnt.mat[i][i]=1;
	
	for(i=0;i<k;i++){
		scanf("%c",&c);
		if(c=='g'){
			scanf("%I64d",&v);
			cnt.mat[n][v-1]++;
		}else if(c=='e'){
			scanf("%I64d",&v);
			for(j=0;j<n+1;j++) cnt.mat[j][v-1]=0;
		}else{
			scanf("%I64d%I64d",&v,&w);
			for(j=0;j<n+1;j++){
				t=cnt.mat[j][v-1];
				cnt.mat[j][v-1]=cnt.mat[j][w-1];
				cnt.mat[j][w-1]=t;
			}
		}
		getchar();
	}

	ans.c=1;
	ans.r=n+1;
	memset(ans.mat,0,sizeof(ans.mat));
	ans.mat[0][n]=1;
}

Matrix MatrixMul(Matrix a,Matrix b){		//稀疏矩阵乘法
	int i,j,v;
	Matrix t;
	t.r=a.r;
	t.c=b.c;
	memset(t.mat,0,sizeof(t.mat));
	for(i=0;i<a.c;i++){
		for(j=0;j<a.r;j++)
			if(a.mat[i][j]){
				for(v=0;v<b.c;v++)
					t.mat[i][v]+=(a.mat[i][j]*b.mat[j][v]);
			}
	}
	return t;
}

void Binary(){					//二分快速幂
	while(m){
		if(m & 1) ans=MatrixMul(ans,cnt);
		cnt=MatrixMul(cnt,cnt);
		m=m>>1;
	}
}

void Output(){
	int i;
	for(i=0;i<n;i++)
		printf("%I64d ",ans.mat[0][i]);
	printf("\n");
}

int main(){
	while(scanf("%I64d%I64d%I64d\n",&n,&m,&k)){
		if(!n && !m && !k) break;
		Input();
		Binary();
		Output();
	}
	return 0;
}


 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值