xmuoj-假币问题

描述

林克有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讲解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值