描述
林克有12枚银币。其中有11枚真币和1枚假币。假币看起来和真币没有区别,但是重量不同。但林克不知道假币比真币轻还是重。
于是他向他朋友约珥借了一架天平,用这架天平称了这些币三次。
如果用天平称两枚硬币,发现天平平衡,说明两枚都是真的。如果用一枚真币与另一枚银币比较,发现它比真币轻或重,说明它是假币。
经过精心的设计,聪明的林克根据这三次称量结果找出假币,并且能够确定假币是轻是重。
如果给你林克的称量数据,你也可以找出假币并且确定假币是轻是重吗?(林克提供的称量数据保证一定能找出假币)。
输入
第一行有一个数字n,表示有n组测试用例。
对于每组测试用例:
输入有三行,每行表示一次称量的结果。林克事先将银币标号为A-L。
每次称量的结果用三个以空格隔开的字符串表示:
天平左边放置的硬币 天平右边放置的硬币 平衡状态。
其中平衡状态用``up'', ``down'', 或 ``even''表示, 分别为右端高、右端低和平衡。天平左右的硬币数总是相等的。
输出
输出哪一个标号的银币是假币,并说明它比真币轻还是重(heavy or light)。
输入样例 1
1 ABCD EFGH even ABCI EFJK up ABIJ EFGH even
输出样例 1
K is the counterfeit coin and it is light.
整体思路:
由于本题的银币数量是有限且比较少的,我们可以采用枚举法,从A开始假设该枚银币是假的+轻的,代入三个已知的式子,看是否都符合,若全都符合,则假设成立,该枚银币为假的+轻的。若从A找到L后还是没有找到符合三个式子的银币,则说明假银币是重的,这个时候就再从A开始假设该枚银币是假的+重的,终会找到符合式子的银币。
现在我们来想这三个提供的条件要怎么用代码表示。
1.首先要先把输入给解决了。这道题我们不能只盯着它的输入样例去写代码,因为输入还可能是
AGHL BDEC even
JKI ADE up
J K even
或者
ABCDEF GHIJKL up
ABC DEF even
I J down
即不是每一边都是4个银币,不能一次存一行,不好处理,所以必须将每一边的银币都分别存进一个字符串里,然后结果也各自储存起来 == > string left[3], right[3], result[3]
2.先搞一个函数来判断此银币为假的+轻的 bool test(char ch,bool islight)
因为我们假设的是此银币为假,所以
当result==even,那么此银币不能出现在天平的左右两边(否则就不平衡了),所以如果我们检索到此银币出现在left或者right,就return false;
当result==top,那么此银币就要出现在右端,所以如果我们在right里面检索不到此银币,return false;
当result==down,那么此银币就要出现在左端,所以如果我们在left里面检索不到此银币,return false;
3.那当我们枚举完假+轻的情况仍然没有找到,还要重新再写一个函数来判断此银币为假的+重的吗?其实不用,当我们用上面一个函数时传入的是 test(char ch,true),那么把true换成false就可以了。
那么三个判断要怎么改呢?top和down的判断结果是要颠倒一下顺序的。为了方便,我们可以创造2个临时字符串l、r储存left和right。
当islight==true时,按照第2步思路写代码,因为用了l和r,就把left变成l,right变成r就可以了;
当islight==false(即假设假银币是比较重的)时,把l和r的内容交换一下,这样子当result==top,原本假的应该在左边,交换l和r之后假的应该在右边,这样子下面的判断思路就照第2步一样了。
这样子就将两种islight的情况的判断都归于同一个代码,节省了不少代码量。
下面是参考代码
#include <iostream>
#include <cstring>
std::string left[3], right[3], result[3];
bool test(char ch, bool islight)
{
std::string c;
c.push_back(ch);
int count = 0;
for (int i = 0; i < 3; i++)
{
std::string l = left[i];
std::string r = right[i];
if (islight == false)
swap(l, r);
switch (result[i][0])
{
case 'e':
{
if (l.find(c) != std::string::npos || r.find(c) != std::string::npos)
{
return false;
}
break;
}
case 'u':
{
if (r.find(c) == std::string::npos)
{
return false;
}
break;
}
case 'd':
{
if (l.find(c) == std::string::npos)
{
return false;
}
break;
}
}
}
return true;
}
int main()
{
int t;
std::cin >> t;
while (t--)
{
for (int i = 0; i < 3; i++)
{
std::cin >> left[i] >> right[i] >> result[i];
}
for (char ch = 'A'; ch <= 'L'; ch++)
{
if (test(ch, true))
{
std::cout << ch << " is the counterfeit coin and it is light. " << std::endl;
break;
}
else if (test(ch, false))
{
std::cout << ch << " is the counterfeit coin and it is heavy. " << std::endl;
break;
}
}
}
return 0;
}
参考链接Andy讲解