POJ1013-Counterfeit Dollar

系统 1795 0

转载请注明出处:優 YoU  http://blog.csdn.net/lyy289065406/article/details/6661421

大致题意:

有一打(12枚)硬币,其中有且仅有1枚假币,11枚真币

用A~L作为各个硬币的代号

假币可能比真币略轻,也可能略重

现在利用天枰,根据Input输入的3次称量,找出假币,并输出假币是轻还是重。

解题思路:

模拟法要考虑的情况较繁琐,可利用简单的逻辑推理进行解题。

注意Input一行代表一次称量,每行有三个字符串,分别为

Left   right     status

代表该次称量时,天枰左盘放的硬币、天枰右盘放的硬币、天枰 右盘 的状态

共三种状态:

Up:右盘上升,说明右盘可能有轻假币,也可能左盘有重假币。

Down:右盘下降,说明右盘可能有重假币,也可能左盘有轻假币。

Even:右盘与左盘平衡,由于假币有且仅有1枚,则说明此时天枰两边的硬币全为真币。

注意题目的字眼:

1、  有且仅有1枚假币

2、  假币相对于真币的重量,可能轻可能重

3、  只称量3次,且称量3次恰好且必能找到假币

4、  每次称量时天枰两边的硬币数目一样

5、  选取哪些硬币称量由input决定

从3、4、5可知,由于无法知道每次选取称量的硬币,那么3次称量可能只选用了几个硬币,也可能仅有一两个硬币没有选上,那么用模拟法去记录每次用于称量的硬币的状态(真假,其中假币又有轻重之分)并推导没有被称量的硬币状态(或状态变化)是很困难的,虽然人很容易做到这点,但计算机却很难去“推导”,因为称量硬币的方法是无规律的且非常多。

那么只能通过适当转化问题后用另一种有效的方法去解决。

虽然称量硬币的方法是无规律且未知的,但是称量硬币后的结果却只有3个,up、down和 even。且当出现even时,天枰两边的硬币必然都为真币,假币必定在余下的硬币之间(这是因为假币有且只有一枚),那么我们就可以定义一个标记数组 zero[]去标记even时的真币,在以后的处理把他们排除在外。

而唯一难以处理的是up和down的状态,因为假币可能轻可能重,则这两种状态都无法得知究竟假币出现在天枰的哪边。

处理up和down状态方法:

当出现up或down状态时,天枰两边的所有硬币都应该被怀疑为假币(已标记必定为真币的硬币不必被怀疑)。

首先time[]记录每个硬币的被怀疑程度,time[i]=0表示该硬币i不被怀疑(即其可能为真币)。定义在up状态盘的硬币为“轻怀疑假币”,通过“--”操作加深其被怀疑为轻假币的程度,“负号”为轻假币的怀疑方向;在down状态盘的硬币为“重怀疑假币”,通过“++”操作加深其被怀疑为重假币的程度,“正号”为重假币的怀疑方向。

那么若一枚真币被怀疑为“轻假币”时,它就可能通过下次称量通过“++”操作取消嫌疑了。初始化所有硬币的怀疑程度均为0。

称量完毕后,找出被怀疑程度最大(注意取绝对值)的硬币,它就是假币。而当其怀疑方向为正时,则其为重假币。为负时,为轻假币。

      
         1
      
      
        //
      
      
        Memory Time 
        
2 // 252K 0MS
3
4 #include < iostream >
5 #include < cmath >
6 using namespace std;
7
8 int main( void )
9 {
10 int cases;
11 cin >> cases;
12 for ( int c = 1 ;c <= cases;c ++ )
13 {
14 char left[ 3 ][ 6 ],right[ 3 ][ 6 ],status[ 3 ][ 6 ];
15
16 int time[ ' L ' + 1 ] = { 0 }; // 标记各个字母被怀疑的次数
17 bool zero[ ' L ' + 1 ] = { false }; // 标记绝对为真币的字母(令天枰平衡的所有字母)
18
19 for ( int k = 0 ;k < 3 ;k ++ )
20 cin >> left[k] >> right[k] >> status[k];
21
22 for ( int i = 0 ;i < 3 ;i ++ )
23 {
24 switch (status[i][ 0 ]) // 检查天枰状态
25 {
26 case ' u ' : // up,天枰左重右轻
27 {
28 for ( int j = 0 ;left[i][j];j ++ )
29 {
30 time[ left[i][j] ] ++ ; // 左重
31 time[ right[i][j] ] -- ; // 右轻
32 }
33 break ;
34 }
35 case ' d ' : // down,天枰左轻右重
36 {
37 for ( int j = 0 ;left[i][j];j ++ )
38 {
39 time[ left[i][j] ] -- ; // 左轻
40 time[ right[i][j] ] ++ ; // 右重
41 }
42 break ;
43 }
44 case ' e ' : // down,天枰平衡
45 {
46 for ( int j = 0 ;left[i][j];j ++ )
47 {
48 zero[ left[i][j] ] = true ; // 绝对真币
49 zero[ right[i][j] ] = true ; // 绝对真币
50 }
51 break ;
52 }
53 }
54 }
55
56 int max =- 1 ; // 查找被怀疑程度最高的硬币(假币)
57 char alpha;
58 for ( int j = ' A ' ;j <= ' L ' ;j ++ )
59 {
60 if (zero[j]) // 绝对真币
61 continue ;
62
63 if (max <= abs(time[j]))
64 {
65 max = abs(time[j]);
66 alpha = j;
67 }
68 }
69
70 cout << alpha << " is the counterfeit coin and it is " ;
71 if (time[alpha] > 0 )
72 cout << " heavy. " << endl;
73 else
74 cout << " light. " << endl;
75 }
76 return 0 ;
77 }

POJ1013-Counterfeit Dollar


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论