问题定义:
赛利有
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.
解题思路
此题中赛利已经设计了正确的称量方案,保证从三组称量数据中能得到唯一的答案。答案可以用两个变量表示:x.假币的标号w.假币是比真币轻还是比真币重。x共有12种猜测;w有2种猜测。根据赛利设计的称量方案,(x,w )的24种猜测中,只有唯一的猜测与三组称量数据都不矛盾。因此,如果猜测 (x,w )满足下列条件,这个猜测就是要找的答案:
在称量结果为"even''的天平两边,没有出现x ;
.
如果w表示假币比真币轻,则在称量结果为"up'' 的天平右边一定出现x、在称量结果为"down''的天平左边一定出现x 如果w表示假币比真币重,则在称量结果为"up'' 的天平左边一定出现
x、在称量结果为"down''的天平右边一定出现x。
具体实现时,要注意两点:
1)选择合适的算法,对于每一枚硬币x逐个试探:
x比真币轻的猜测是否成立?猜测成立则进行输出。
x比真币重的猜测是否成立?猜测成立则进行输出。
2)选择合适的数据结构
以字符串数组存储称量的结果。每次称量时,天平左右最多有6枚硬币。因此,字符串的长度需要为7,最后一位存储字符串的结束符’\0’,便于程序代码中使用字符串操作函数。
char left[3][7], right[3][7], result[3][7];
注意事项:
1.对于经常要用到的数据,先预处理
2.仔细分析问题,减少搜索空间
代码示例:
/* * *Declaration:The author of <<Accelerated C++>> has wrote in the end of that book: As you look for reading materimal, keep in mind that books on the shelf do not make you a better programmer. Ultimately, the only way to improve your programming is to write programs. >这些程序来自一些ACM书籍,作者只为提高编程能力,实现书中例题或练习。如有侵权,请联系作者,作者将立即删除。 * *联系邮箱:mingxinglai#gmail.com * */ #include <stdio.h> #include <string.h> char left[3][7], right[3][7], result[3][5]; bool isHeavy( char ); bool isLight( char ); int main(int argc, char* argv[]) { int n; char c; scanf("%d", &n); while( n-- ) { for( int i = 0; i < 3; i++) scanf("%s%s%s", left[i], right[i], result[i]); for( c = 'A'; c <= 'L'; c++ ) { if( isLight( c ) ) { printf("%c is the counterfeit coin and it is light.\n", c); break; } if( isHeavy( c ) ) { printf("%c is the counterfeit coin and it is heavy.\n", c); break; } } } return 0; } bool isLight( char x ) { int i; for( i = 0; i < 3; i++) switch( result[i][0] ) { case 'u': if( strchr( right[i], x) == NULL) return false; break; case 'e': if( strchr( right[i], x) != NULL || strchr( left[i], x) != NULL ) return false; break; case 'd': if( strchr( left[i], x) == NULL ) return false; break; } return true; } bool isHeavy( char x ) { int i; for( i = 0; i < 3; i++) switch( result[i][0] ) { case 'u': if( strchr( left[i], x) == NULL) return false; break; case 'e': if( strchr( right[i], x) != NULL || strchr( left[i], x) != NULL ) return false; break; case 'd': if( strchr( right[i], x) == NULL ) return false; break; } return true; }