POJ 1013--Counterfeit Dollar(假币问题)(枚举,假设)

POJ 1013–Counterfeit Dollar(假币问题)(枚举,假设)

描述

赛利有12枚银币。其中有11枚真币和1枚假币。假币看起来和真币没有区别,但是重量不同。但赛利不知道假币比真币轻还是重。于是他向朋友借了一架天平。朋友希望赛利称三次就能找出假币并且确定假币是轻是重。例如:如果赛利用天平称两枚硬币,发现天平平衡,说明两枚都是真的。如果赛利用一枚真币与另一枚银币比较,发现它比真币轻或重,说明它是假币。经过精心安排每次的称量,赛利保证在称三次后确定假币。

输入

第一行有一个数字n,表示有n组测试用例。
对于每组测试用例:
输入有三行,每行表示一次称量的结果。赛利事先将银币标号为A-L。每次称量的结果用三个以空格隔开的字符串表示:天平左边放置的硬币 天平右边放置的硬币 平衡状态。其中平衡状态用up’’,down”, 或 “even”表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的。

输出

输出哪一个标号的银币是假币,并说明它比真币轻还是重(heavy or light)。

样例输入

1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even

样例输出

K is the counterfeit coin and it is light.

解题思路:

枚举某一硬币的类型,先定位假币(重量大1或 重量小-1),再将其还原为真币重量0
需要注意以下几点:
一、一定有假币存在且数量为1.
二、天平两边可以放最多6个。
三、枚举过程中不满足即可跳出,如果三个都满足即可返回1,当其为假币时,满足输入的三个条件,就确定假设为真,即当前第i(字母表示)个为假币.

代码实现:

#include
#include
#include
using namespace std;
char a[3][10],b[3][10],c[3][10];//记录左天平a,右天平b,状态c 三种条件情况
int S[15];//记录当前硬币是第几个
int G()//判断假设是否满足三个条件
{
	int left,right;
	for(int i=0;i<3;i++)
	{
		left=0;
		right=0;
		for(int j=0;j<6&&a[i][j]!=0&&b[i][j]!=0;j++)
		{
			left+=S[a[i][j]-'A'];
			right+=S[b[i][j]-'A'];
		}
		if(left>right&&c[i][0]!='u')return 0;
		if(left<right&&c[i][0]!='d')return 0;
		if(left==right&&c[i][0]!='e')return 0;
	}
	return 1;
}
int main()
{
	int x;
	scanf("%d",&x);
	getchar();
	while(x--)
	{
		for(int i=0;i<3;i++)
		{
			scanf("%s %s %s",a[i],b[i],c[i]);
		}
		memset(S,0,sizeof(S));//设硬币重量默认都为0
		for(int i=0;i<12;i++)
		{
			S[i]=1;//先假设当前i这个硬币是重的假币记为1
			G();
			if(G()==1){printf("%c is the counterfeit coin and it is heavy.\n",'A'+i);break;}
			/*如果3条件全部满足符合则输出当前正确的假设*/
			S[i]=-1;//先假设当前i这个硬币是轻的假币记为-1
			G();
			if(G()==1){printf("%c is the counterfeit coin and it is light.\n",'A'+i);break;}
			/*如果3条件全部满足符合则输出当前正确的假设*/
			S[i]=0;//将当前硬币记录为真币,进行后续运算
		}
	}
}

你可能感兴趣的:(c/c++)