ABCD EFGH even
ABCI EFJK up
ABIJ EFGH even
注意:天平左右的硬币数量总是相等的。
可以计算得出K是假币,且比真币更轻。
思路:从12个一样的钱币中找出一个未知重量的假币,称3次,给出结果,判断假币及其相对重量。
用模拟的方法很容易想到排除法,即分情况讨论:
当结果为even时,说明称上的几个钱币一定是真币
当结果为up时,说明其余的钱币一定是真币,并且左边钱币中有一个重的或者右边钱币中有一个轻的
当结果为down时,说明其余的钱币一定是真币,并且左边钱币中有一个轻的或者右边钱币中有一个重的
模拟的方法就是用一个数组记录每个钱币的状态,初始为-1,如果一定为真币记为0,如果可能较重记为2,如果可能较轻记为1,最后只要判断大于0的钱币一定为假币,而相应的状态表示它的相对重量。
可是实现时要考虑很多种细节,最重要的一点就是加一个记录上次状态的数组,因为如果上次判断一个钱币为真币,则不论下次结果如何,它还应当是真币;如果上次判断它可能较轻,而本次判断它可能较重,则它一定是真币!用循环及判断可做出来。
个人感觉:这道题刚开始我没看明白是什么意思,然后又看了题目的中文翻译,才理解了一点,但是还是没能全部理解清楚。所以参考了下网友的算法,觉得很容易,就是我用的这个算法。有个是用指针的算法,但是指针比较麻烦,所以我用了这种比较理解起来比较简单的算法。
代码如下:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main()
{
int n, i, j, b, l;
int real[16], t[16];
char left[9], right[9], r[5];
char s[3][17]= {"ABCDEFGHIJKL","light","heavy"};
cin>>n;
while(n--)
{
memset(real,-1,sizeof(real));
for(i=0;i<3;i++)
{
cin>>left>>right>>r;
b=strcmp(r,"even");
l=strlen(left);
if(b==0)
{
for( j= 0; j< l; j++ )
real[left[j]-'A']= real[right[j]-'A']= 0;
}
else if(b==-1)
{
memcpy(t,real,sizeof(real));
memset(real,0,sizeof(real));
for( j= 0; j< l; j++ )
real[left[j]-'A']= 1, real[right[j]-'A']= 2;
for( j= 0; j< 16; j++ )
if( t[j]>=0 && t[j]!=real[j] ) real[j]= 0;
}
else
{
memcpy(t,real,sizeof(real));
memset(real,0,sizeof(real));
for( j= 0; j< l; j++ )
real[left[j]-'A']= 2, real[right[j]-'A']= 1;
for( j= 0; j< 16; j++ )
if( t[j]>=0 && t[j]!=real[j] ) real[j]= 0;
}
}
for( i= 0; i< 16; i++ )
if( real[i]> 0 )
printf("%c is the counterfeit coin and it is %s.\n",s[0][i],s[real[i]]);
}
return 0;
}