POJ1166

这道题目和1830比较类似,1830是求解的个数,这道题目相当于求线性方程组的整数解(注意,这道题目的陷阱之一就是解出来的结果可能不是整数,反正我的代码一开始就是有的是小数)

题目主要内容:有9个钟,其中9个操作方法来扳动上面的指针,每个操作每次只能把指针移动90度,且每个操作是对一组钟进行操作(即执行每个操作之后有几个钟的状态被改变了90度而不是单独某个钟的状态改变了90度)。操作与其影响的钟的对应表如表一所示:


表一

题目要求的是给出这9个钟的初始状态(0表示指向12点,1表示指向3点,2表示指向6点,3表示指向6点)用操作1-9采用最少的移动次数操作这些钟,使它们都指向12点。

思路:根据操作与钟表的关系我们可以构造一个关系矩阵,如表二所示


行表示钟,列表示操作,例如,操作1,2,4被采用之后A都会受到影响,移动一步(即90度)。所以题目的意思就是求操作1-9都被操作了多少次,使得每个钟表从初始状态被调整到12点的那个状态,即每个钟表的状态变化=操作1*操作次数+操作2*操作次数+…+操作9*操作次数。


用测试数据作为例子说明一下:


但是注意,1-9操作的次数并不是这道题目的输出结果,它要求咱们把每个操作的过程输出来,也就是如果我操作了2次9号操作那么就输出9 9。还是看测试数据,虽然求出来的结果是


但是输出的结果是4,5,8 ,9

(这里之前卡了一下,一开始我以为操作出现的顺序会影响钟表的状态,但是仔细想一下发现操作的出现次序与钟表的最后状态没关系,即操作顺序 1  3   1与操作1   1   3是一样的,若有疑问可以自己模拟操作一下。所以只需要求出每个操作的操作次数,从小到大把次数对应的操作序号输出就可以了。)

陷阱1:求解出线性方程组的解的时候,有的时候出现非整数解的情况,这说明按这个数移动是最小的移动数,但是操作不了,那我们只能不断地再状态变化上面再加上一轮(即4)使得求得的数是整数。

陷阱2:求解出的解释负数,即往负方向转能更快到达12点的状态,但是题目里没有说可以用负方向转的,所以只能在其上面不断的加上一轮使得移动的次数变成正数。

代码:

#include<iostream>
#include<cmath>
using namespace std;
int a[9][9]={{1,1,0,1,0,0,0,0,0},
			{1,1,1,0,1,0,0,0,0},
			{0,1,1,0,0,1,0,0,0},
			{1,0,0,1,1,0,1,0,0},
			{1,0,1,0,1,0,1,0,1},
			{0,0,1,0,1,1,0,0,1},
			{0,0,0,1,0,0,1,1,0},
			{0,0,0,0,1,0,1,1,1},
			{0,0,0,0,0,1,0,1,1}};
float b[9][10];
void convert(int n,int m)
{
	int i,j,t,swapline,tag,time;
	float mul,cal[10];
	for(i=0;i<n;i++)
	{
		//找到不为0的那行;
		
		for(j=i;j<n;j++)
		{
			if(b[j][i]!=0)
				break;
		}
		//若当前要处理的行的位置等于0,那么把不等于0的与它交换
		if(j<n)
		{
			if(j!=i)
			{
				swapline=j;
				for(j=i;j<m;j++)
				{
					t=b[swapline][j];
					b[swapline][j]=b[i][j];
					b[i][j]=t;
				}
			}
			//将子矩阵处理成第一列为0 的
			for(j=i+1;j<n;j++)
			{
				tag=0;
				if(b[j][i]!=0)
				{
					mul=-b[i][i]/b[j][i];
					for(t=i;t<m;t++)
					{
						b[j][t]=mul*b[j][t]+b[i][t];
					}
				}

			}
		}

	}
	for(j=0;j<n;j++)
	{
		tag=0;
		for(t=j;t<m;t++)
		{
			if((int)b[j][t]!=b[j][t])
				tag=1;
		}
		if(tag)
		{
			time=2;
			while(tag)
			{
				tag=0;
				for(t=j;t<m;t++)
				{
					cal[t]=b[j][t]*time;
					if((int)cal[t]!=cal[t])
						tag=1;
				}
				time++;
			}
			for(t=j;t<m;t++)
				b[j][t]=cal[t];
		}
	}
}
int main()
{

	int s[9];
	float result[9],sum,rl,right;
	int i,j,t,time,tp;
	for(i=0;i<9;i++)
		for(j=0;j<9;j++)
			b[i][j]=a[i][j];
	for(i=0;i<9;i++)
	{
		scanf("%d",&t);
		s[i]=(4-t)%4;
		b[i][9]=s[i];
	}
	convert(9,10);
	for(i=8;i>=0;i--)
	{
		sum=0;
		for(j=8;j>i;j--)
		{
			sum+=result[j]*b[i][j];
		}
		time=0;
		rl=0.1;
		while((int)rl!=rl)
		{
		right=b[i][9]-sum+4*time;
		rl=right/(b[i][i]);
		time++;
		}
		time=1;
		while(rl<0)
		{
		rl+=time*4;
		}
		result[i]=(int)rl%4;
	}
	for(i=0;i<9;i++)
	{
		if(result[i]>0)
		{
			for(j=0;j<result[i];j++)
				printf("%d ",i+1);
		}
	}

	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值