前面说完美立方,生理周期中的枚举都是比较明显的枚举,有些枚举条件是隐藏的枚举条件,下面通过例题来说明寻找隐藏的枚举条件。
1、题目描述
-
例题:POJ1013称硬币
有12枚硬币。其中有11枚真币和1枚假币。假币和真币重量不同, 但不知道假币比真币轻还是重。现在用一架天平称了这些币三次,告诉你称的结果,请你找出假币并且确定假币是轻是重(数据保证一能找出来)。 -
输入
第一行是测试数据组数。
每组数据有三行,每行表示一次称量的结果。银币标号为A-L。每次称量的结果用三个以空格隔开的字符串表示:天平左边放置的硬币,天平右边放置的硬币平衡状态。其中平衡状态用"up",“down”,或"even"表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的。 -
输出
输出哪一个标号的银币是假币,并说明它比真币轻还是重。 -
输入样例
1
ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even -
输出样例
K is the counterfeit coin and it is light.
2、解题思路
这个题目与智力题不同,不是让你设计称量方法,而是已经给出称量方法,有了称量结果,并且保证在结果中一定可以找出哪个是假币,这个假币是轻还是重。
对于解题思路,这里是在讲解枚举,大方向肯定是枚举嘛,一共有12个硬币,对每一个硬币进行枚举。对于每一枚硬币先假设它是假币且是轻的,拿这个假设带入三次称量的结果中,看是否符合称量结果。如果符合,问题即解决,确定这个硬币是假币且轻。如果不符合,就假设这个硬币是假币且是重的,看是否符合称量结果。把所有硬币都试一遍,一定能找到这个假币且判判断出假币是轻还是重。
#include<iostream>
using namespace std;
char Left[3][6]; //天平左边硬币
char Right[3][6]; //天平右边硬币
char result[3][4]; //称重结果
//light为true时,假设假币为轻,为false时,假设假币为重
bool IsFake(char c, bool light);
int main()
{
int t;//数据的组数
cin >> t;
while (t--)
{
for (int i = 0; i < 3;i++)//每一组有三次称量
cin >> Left[i] >> Right[i] >> result[i];
for (char c = 'A'; c <= 'L'; c++)
{
if (IsFake(c, true))
{
cout << c << " is the counterfeit coin and it is light." << endl;
break;
}
if (IsFake(c, false))
{
cout << c << " is the counterfeit coin and it is heavy." << endl;
break;
}
}
}
return 0;
}
bool IsFake(char c, bool light)
{
for (int i = 0; i < 3; i++)
{
char *pLeft, *pRight;//指向天平两边的字符串
if (light == true)
{
pLeft = Left[i];
pRight = Right[i];
}
else //如果假设假币是重的,则把称量结果左右对换
{
pLeft = Right[i];
pRight = Left[i];
}
switch (result[i][0])
{
case 'u': //天平右边高
if (strchr(pRight, c) == NULL)
return false;
break;//break作用是结束switch循环,不加会进入下一个case
case 'e': //天平两端等高
if (strchr(pLeft, c) ||strchr(pRight, c))
return false;
break;
case 'd': //天平右边低
if (strchr(pLeft, c) == NULL)
return false;
break;
}
}
return true;
}
对strchr函数说明如下:
char *strchr(const char * _Str,char _Val)
功能:查找字符串_Str中首次出现字符_Val的位置
说明:返回首次出现_Val的位置的指针,返回的地址是被查找字符串指针开始的第一个与Val相同字符的指针,如果Str中不存在Val则返回NULL。
返回值:成功则返回要查找字符第一次出现的位置,失败返回NULL
3、总结
寻找隐藏的枚举条件