称硬币
问题描述
有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.
解题思路:
对于每一枚硬币先假设它是轻的,看这样是否符合称量结果。如果符合,问题即解决。如果不符合就假设它是重的,看是否符合称量结果。把所有硬币都试一遍,一定能找到特殊硬币。
代码:
#include<stdio.h>
#include<string.h>>
int main()
{
int n,s=3,k=3,i;
char a[3][6],b[3][6],c[3][6],d;
scanf("%d",&n);
while(n-->0)
{
for(int i=0;i<3;i++)
scanf("%s %s %s",&a[i],&b[i],&c[i]);
for(d='A';d<='L';d++)//从A开始挨个试
{
for(i=0;i<3;i++)//先假设是轻的
{
char*pleft=a[i];//不用指针不好用strchr函数进行判断
char*pright=b[i];
switch(c[i][0])
{
case 'u': if(strchr(pright,d)==NULL)//右边高说明硬币应该在右边,如果右边没有则对S减一
s--;//S初值设为3,一次不满足就减1,只有三次都满足才不会改变其初值3
break;
case 'e' : if(strchr(pleft,d)||strchr(pright,d))//两边一样说明其既不在左边也不在右边
s--;
break;
case 'd' : if(strchr(pleft,d)==NULL)//右边低说明其在左边,如果左边没有则不满足题目中给的其中一个条件 ,对S减一
s--;
break;
}
}
if(s==3)//3次循环下来如果 S的初值不变说明3个条件都满足则输出,程序结束。
{
printf(" %c is the counterfeit coin and it is light.\n",d);
return 0;
}
else//如果S的值变了说明不满足条件,将S修改为初始值方便对下一枚硬币进行判断
{
s=3;
}
for(i=0;i<3;i++)//假设是重的
{
char*pleft=a[i];
char*pright=b[i];
switch(c[i][0])
{
case 'u': if(strchr(pleft,d)==NULL)//右边高,又因硬币此处假设是沉的,说明硬币应该在左边,如果左边没有则对K减一
k--;
break;
case 'e' : if(strchr(pleft,d)||strchr(pright,d))//两边一样说明其既不在左边也不在右边
k--;
break;
case 'd' : if(strchr(pright,d)==NULL)//右边低说明其在右边,如果右边没有则不满足题目中给的其中一个条件 ,对K减一
k--;
break;
}
}
if(k==3)//K仍然为初值3,输出,程序结束 。
{
printf(" %c is the counterfeit coin and it is heavy.\n",d);
return 0;
}
else//初值改变,还原为默认初值。
{
k=3;
}
}
}
}
这是我首次想到的实现方法,比较繁琐。
标准答案:
#include <iostream>
#include <cstring>
using namespace std;
char Left[3][7];
char Right[3][7];
char result[3][7];
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.\n";
break;
}
else if(IsFake(c, false))
{
cout << c <<" is the counterfeit coin and it is heavy.\n";
break;
}
}
}
return 0;
}
bool IsFake(char c, bool light)
{
for(int i=0; i<3; i++)
{
char *pLeft;
char *pRight;
if(light)
{
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;
case 'e':
if( strchr(pRight, c) || strchr(pLeft, c))
return false;
break;
case 'd':
if( strchr(pLeft, c) == NULL)
return false;
break;
}
}
return true;
}