解题思路:
本题依旧是使用枚举法解决。枚举每一个硬币,先假设被枚举到的这个硬币是轻的,看看是否符合三种称量结果,倘若符合,即可找到假币。倘若不符合,则假设被枚举到的这个硬币是重的,看看是否符合三种测量结果,同理,倘若符合则找到假币。倘若不符,则所拿硬币是真币(因为假币不是轻就是重,而且有且只有一个假币),继续枚举下一枚硬币直到找到假币为止。
代码实现:
#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 light.\n";
break;
}
//都不符合表示不是假币,换下一个币
}
}
}
/**
* 判断传入的硬币是不是假币
* @param c 传入的硬币编号
* @param light true就是轻的 false就是重的
* @return 返回true表示是假币
*/
bool isFake(char c,bool light){
//有三组数据,看看这三组数据是否都满足假设
for (int i = 0; i < 3; ++i) {
char *pleft,*pright;
//因为天平反映的是右边的情况
//当假设假币轻时,若假币在右边则右边up,在左边则右边down
//当假设假币重时,若假币在右边则右边down,在左边则右边up
//当假设假币重时,用指针调换天平的两侧,使得switch中pright意表天平左边
//pleft意表天平右边
if (light){
//假设假币是轻的
pleft = Left[i];//第i次称量中天平左边所放的字符串(硬币编号)
pright = Right[i];
} else {
//假设假币是重的
pleft = Right[i];
pright = Left[i];
}
switch (result[i][0]) {
//记得这里是得循环三次中的判断呢
//如果第i组数据的结果是
case 'u':{
//up,说明天平右边轻
if (strchr(pright,c)==NULL){
//如果这个这个比较轻的硬币不在右边,则矛盾,该硬币不是假币
return false;
}
break;
}
case 'e':{
//一样重
if (strchr(pleft,c)||strchr(pright,c)){
//如果这个假币存在天平左边或右边,天平不可能平衡,则矛盾
return false;
}
break;
}
case 'd':{
//右边重
if (strchr(pleft,c)==NULL){
//如果右边比较重,这个比较轻的假币却不在左边,则矛盾
return false;
}
break;
}
}
}
//循环结束,对于三种情况,硬币的假设都成立,所以是假币
return true;
}