poj 3735 矩阵行列变换

    这题是矩阵运算的经典题目。
    可以将peanut初始化为{{0},{0},{0},{1}},然后对peanut矩阵进行变换(行变换,可以对单位矩阵操作,然后放在左边乘以peanut。列变换则放在右边)。还有矩阵的运算符合结合率,不符合交换率。
    进行矩阵的N次方运算的时候,我一直没用二进制的思想,一直在模拟递归的过程,结果不断超时,感觉复杂度跟二进制的思想差不多的,奇怪了。后来用了二进制的思想才过了。二进制的思想就是不断进行的平方的运算,如果遇到1就累加上去。

    
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct MATRIX
{
	long long  m[110][110];
};
MATRIX mul(MATRIX num1,int n1,int m1,MATRIX num2,int n2,int m2)//m1 = n2
{
	MATRIX res;
	memset(&res, 0, sizeof(res));
	int i,j,k;
	{
		for(i = 0; i <= n1; i++)
		{
			for(k = 0; k <= m1; k++)
			{
				if(num1.m[i][k] != 0)
				{
					for(j = 0; j <= m2; j++)
					{
						res.m[i][j] += num1.m[i][k] * num2.m[k][j];

					}
				}
			}
		}
	}

	return res;
}
MATRIX POW(MATRIX num1,int k,int n)
{
	/*	int cnt = 0;
		int sta[50];
		cnt = -1;
		while(k)
		{
		if((k & 1) == 1)
		{
		sta[++cnt] = 1;
		}
		else
		{
		sta[++cnt] = 0;
		}
		k = (k >> 1);

		}
		MATRIX  res;
		cnt--;
		MATRIX first;
		memcpy(&first,&num1,sizeof(first));
		while(cnt != -1)
		{
		if(sta[cnt] == 0)
		{
		num1 = mul(num1,n,n,num1,n,n);
		}
		else
		{
		num1 = mul(num1,n,n,num1,n,n);
		num1 = mul(first,n,n,num1,n,n);
		}
		cnt--;
		}
	 *///模拟递归
	MATRIX res;
	memcpy(&res,&num1,sizeof(num1));
	memset(&res,0,sizeof(res));
	int i;
	for(i = 0; i <= n; i++)
	{
		res.m[i][i] = 1;
	}
	while(k)
	{
		if(k & 1)
		{
			res = mul(res,n,n,num1,n,n);

		}
		num1 = mul(num1,n,n,num1,n,n);
		k >>= 1;
	}//二进制思想
	return res;
}
int main()
{
	int n,k,m;
	while(scanf("%d %d %d",&n,&k,&m) != EOF)
	{
		if(n == 0 && k == 0 && m == 0)
		{
			break;
		}
		int i;
		char str[2];
		MATRIX cat;
		memset(&cat, 0, sizeof(cat));
		cat.m[n][0] = 1;
		MATRIX one;
		memset(&one, 0, sizeof(one));
		for(i = 0; i <= n; i++)
		{
			one.m[i][i] = 1;
		}
		int j;
		for(j = 0; j < m; j++)
		{
			scanf("%s",str);
			int from,to;
			if(strcmp(str,"g") == 0)
			{
				scanf("%d", &from);
				one.m[from - 1][n]++;
			}
			else if(strcmp(str,"e") == 0)
			{

				scanf("%d",&from);
				for(i = 0;i<= n; i++)
				{
					one.m[from - 1] [i] = 0;
				}
			}
			else if(strcmp(str,"s") == 0)
			{
				scanf("%d %d", &from, &to);
				from--;
				to--;
				int temp[110];
				for(i = 0 ;i <= n; i++)
				{
					temp[i] = one.m[from][i];
					one.m[from][i] = one.m[to][i];
					one.m[to][i] = temp[i];

				}
			}
		}
		one = POW(one,k,n);
		cat = mul(one,n,n,cat,n,1);
		for(i = 0; i < n; i++)
		{
			printf("%lld%c",cat.m[i][0],i==n-1? '\n':' ');
		}
	}


}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值