poj 2692 假币问题

本文详细介绍了通过称量硬币找出假币及其轻重的方法,包括初始思路的误区、改进算法以及最终实现过程。通过三次称量确保准确识别出异常硬币。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很坑爹 。。。

-------------------------------------------------------------------------------------------------------

Time Limit: 
1000ms 
Memory Limit: 
65536kB
Description
赛利有12枚银币。其中有11枚真币和1枚假币。假币看起来和真币没有区别,但是重量不同。但赛利不知道假币比真币轻还是重。于是他向朋友借了一架天平。朋友希望赛利称三次就能找出假币并且确定假币是轻是重。例如:如果赛利用天平称两枚硬币,发现天平平衡,说明两枚都是真的。如果赛利用一枚真币与另一枚银币比较,发现它比真币轻或重,说明它是假币。经过精心安排每次的称量,赛利保证在称三次后确定假币。
Input
第一行有一个数字n,表示有n组测试用例。
对于每组测试用例:
输入有三行,每行表示一次称量的结果。赛利事先将银币标号为A-L。每次称量的结果用三个以空格隔开的字符串表示:天平左边放置的硬币 天平右边放置的硬币 平衡状态。其中平衡状态用``up'', ``down'', 或 ``even''表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的。
Output
输出哪一个标号的银币是假币,并说明它比真币轻还是重(heavy or light)。
Sample Input
1
ABCD EFGH even 
ABCI EFJK up 
ABIJ EFGH even 

Sample Output
K is the counterfeit coin and it is light. 

---------------------------------------------------------------------

      最开始的想法为先将所有正常的硬币找出来(even两端的),然后对于三次称量结果,读每次称量左右的硬币,如果硬币不是正常的,那么根据称量的结果(up或者down)可以判断出硬币的轻重。这种想法对于题目中例子能够判断出正确结果,但是对于测试数据如

ABCD EFGH even
IJ KA up
JK AB up

不能得出正确结果,首先只能判断出正常的八个硬币,其余的四个硬币都出现在了up或者down的语句中,这样的结果是不正确的。

     然后考虑将称量的语句分类,将生成up_left,up_right,down_left,down_right字符串,每次读到了相应语句,则将左右的字母分别加到相应的字符串末尾,然后对于12个硬币,依次判断

for(i=0;i<12;i++){
				c='A'+i;
				if(even.toString().indexOf(c)!=-1)
					continue;
				if(!up_right.toString().equals("")&&!down_left.toString().equals("")){
					if(up_right.toString().indexOf(c)!=-1&&down_left.toString().indexOf(c)!=-1){
						sresult=(char)c+" is the counterfeit coin and it is light.";
						break;
					}
				}
				else if(up_right.toString().equals("")&&!down_left.toString().equals("")){
					if(down_left.toString().indexOf(c)!=-1){
						sresult=(char)c+" is the counterfeit coin and it is light.";
						break;
					}
				}
				else if(down_left.toString().equals("")&&!up_right.toString().equals("")){
					if(up_right.toString().indexOf(c)!=-1){
						sresult=(char)c+" is the counterfeit coin and it is light.";
						break;
					}
				}
				
				if(!up_left.toString().equals("")&&!down_right.toString().equals("")){
					if(up_left.toString().indexOf(c)!=-1&&down_right.toString().indexOf(c)!=-1){
						sresult=(char)c+" is the counterfeit coin and it is heavy.";
						break;
					}
				}
				else if(up_left.toString().equals("")&&!down_right.toString().equals("")){
					if(down_right.toString().indexOf(c)!=-1){
						sresult=(char)c+" is the counterfeit coin and it is heavy.";
						break;
					}
				}
				else if(down_right.toString().equals("")&&!up_left.toString().equals("")){
					if(up_left.toString().indexOf(c)!=-1){
						sresult=(char)c+" is the counterfeit coin and it is heavy.";
						break;
					}
				}
			}

结果对于测试数据

ABCD EFGH even
IJ KA up
JK AB up

还是不能得到正确的结果,因为此数据中只有up,那么一旦一个硬币出现在了up_left中,那么它就会被判断为重。


然后看了书上的思路,发现是对于每一个硬币,放入三条称量语句中判断它是否轻或者重,

int isLight(char c)
{
	int j;
	for (j=0;j<3;j++)
	{
		if (s[j][2][0]=='u')
		{
			//如果该字母出现在up右端(高的那端),那么它就不是轻的
			if (strchr(s[j][1],c)!=NULL)
				return false;
		}
		if (s[j][2][0]=='e')
		{
			//如果该字母出现在平衡称量语句中
			if (strchr(s[j][0],c)||strchr(s[j][1],c))
				return false;
		}
		if (s[j][2][0]=='d')
		{
			//如果该字母出现在down左端(高的那端),那么它就不是轻的
			if (strchr(s[j][0],c)!=NULL)
				return false;
		}
	}
	return true;
}

但是这种思路其实是错误的,出现在高的那端除了轻的硬币还可能是正常的硬币。

于是改代码如下

int isLight(char c)
{
	int j;
	for (j=0;j<3;j++)
	{
		if (s[j][2][0]=='u')
		{
			//如果该字母没有出现在up右端(高的那端),那么它就一定不是轻的
			if (strchr(s[j][1],c)==NULL)
				return false;
		}
		if (s[j][2][0]=='e')
		{
			if (strchr(s[j][0],c)||strchr(s[j][1],c))
				return false;
		}
		if (s[j][2][0]=='d')
		{
			//如果该字母没有出现在down左端(高的那端),那么它就一定不是轻的
			if (strchr(s[j][0],c)==NULL)
				return false;
		}
	}
	return true;
}

另一个函数int isHeavy(char c)同理

#include <iostream>
#include "string.h"
using namespace std;
char s[3][3][13];
int isLight(char c)
{
	int j;
	for (j=0;j<3;j++)
	{
		if (s[j][2][0]=='u')
		{
			//如果该字母没有出现在up右端(高的那端),那么它就一定不是轻的
			if (strchr(s[j][1],c)==NULL)
				return false;
		}
		if (s[j][2][0]=='e')
		{
			if (strchr(s[j][0],c)||strchr(s[j][1],c))
				return false;
		}
		if (s[j][2][0]=='d')
		{
			//如果该字母没有出现在down左端(高的那端),那么它就一定不是轻的
			if (strchr(s[j][0],c)==NULL)
				return false;
		}
	}
	return true;
}
int isHeavy(char c)
{
	int j;
	for (j=0;j<3;j++)
	{
		if (s[j][2][0]=='u')
		{
			if (strchr(s[j][0],c)==NULL)
				return false;
		}
		if (s[j][2][0]=='e')
		{
			if (strchr(s[j][0],c)||strchr(s[j][1],c))
				return false;
		}
		if (s[j][2][0]=='d')
		{
			if (strchr(s[j][1],c)==NULL)
				return false;
		}
	}
	return true;
}
int main()
{
	int T,i;
	char c;
	cin>>T;
	while(T--)
	{
		cin>>s[0][0]>>s[0][1]>>s[0][2]>>s[1][0]>>s[1][1]>>s[1][2]>>s[2][0]>>s[2][1]>>s[2][2];
		for (i=0;i<12;i++)
		{
			c=(char)(i+'A');
			if (isLight(c))
			{
				cout<<c<<" is the counterfeit coin and it is light."<<endl;
				break;
			}
			if (isHeavy(c))
			{
				cout<<c<<" is the counterfeit coin and it is heavy."<<endl;
				break;
			}
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值