欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-13 17:06:49
...

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<cstdio>
#include<string>
#include<iostream>
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;//将当前硬币记录为真币,进行后续运算
		}
	}
}