原题:
http://acm.fzu.edu.cn/problem.php?pid=1003
分析:
经典的题目(大部分版本是区分苹果).这题最关键的就是充分挖掘每次称得的结果所提供的信息.
这题使用了一个包含12个元素的整型数组,用来标记对应的硬币的状态.
* 未知标记为2
* 正常标记为0
* 可能轻标记为-1
* 可能重标记为1.
下面结合称出的结果说明解题方法:
1) 平衡 : 既然是平衡,那么天平上的硬币就都是正常的.那就都标记为0,且不再改变(标记为0,就确定是正常的).
2)右边高: 可能一个重的假硬币在左边,也可能一个轻的假硬币在右边.这要分情况讨论.
* 被称的硬币是"未知"状态: 在左边就标记为重,在右边就标记为轻.
* 被称的硬币已经被标记为"可能为重":在左边的不改变状态.在右边的标记为正常.(先是"可能为重",后又"可能为轻",那么就是正常的)
* 被称的硬币已经被标记为"可能为轻":在左边的标记为正常.在右边就不改变状态.
一次不平衡的结果还隐藏着,不再天平上的硬币都是"正常"的信息.所以,标记此次没称的硬币为"正常".
3) 右边低: 与"2) 右边高" 同理.
伪代码:
MARK-LIGHT-COINS(arr[], len)
1 for i ← 1 to len
2 do if current coin state is "Heavy"
3 then change current coin state to "True"
4 if current coin state is "Unknow"
5 then change current coin state to "Light"
源码:(VC++)
#include <stdio.h> #include <string.h> const int WEIRHING_TIMES = 3; const int ONE_SIDE_MAXN = 6; const int STATE_MAXLEN = 4; const int COINS_MAXN = 12; int coins[COINS_MAXN]; char leftSide[ONE_SIDE_MAXN + 1], rightSide[ONE_SIDE_MAXN + 1], state[STATE_MAXLEN + 1]; void MarkTrueCoins(char arr[], int len); void MarkLightCoins(char arr[], int len); void MarkHeavyCoins(char arr[], int len); void MarkRestCoinsTrue(char a[], char b[], int len); int main() { //freopen("input.txt", "r", stdin); int T; scanf("%d", &T); for(int testNum = 0; testNum < T; testNum++) { int i; //初始标记所有硬币状态为"2".正常为"0",轻为"-1",重为"1". for(i = 0; i < COINS_MAXN; i++) { coins[i] = 2; } for(i = 0; i < WEIRHING_TIMES; i++) { memset(leftSide, 0, sizeof(leftSide)); memset(rightSide, 0, sizeof(rightSide)); memset(state, 0, sizeof(state)); //读取左边,右边,天平状态 scanf("%s%s%s", leftSide, rightSide, state); int len = strlen(leftSide); if('e' == state[0]) { //被测硬币都正常,标记为正常状态 MarkTrueCoins(leftSide, len); MarkTrueCoins(rightSide, len); } else if('u' == state[0]) { MarkLightCoins(rightSide, len); MarkHeavyCoins(leftSide, len); //不平衡的结果,说明其余的硬币是正常的. MarkRestCoinsTrue(leftSide, rightSide, len); } else { MarkHeavyCoins(rightSide, len); MarkLightCoins(leftSide, len); MarkRestCoinsTrue(leftSide, rightSide, len); } } int pos; for(pos = 0; pos < COINS_MAXN; pos++) { if(1 == coins[pos] || -1 == coins[pos]) { break; } } if(-1 == coins[pos]) { printf("%c is the counterfeit coin and it is light.\n", 'A' + pos); } else { printf("%c is the counterfeit coin and it is heavy.\n", 'A' + pos); } } return 0; } void MarkTrueCoins(char arr[], int len) { int i; for(i = 0; i < len; i++) { coins[arr[i] - 'A'] = 0; } } void MarkLightCoins(char arr[], int len) { int i; for(i = 0; i < len; i++) { if(2 == coins[arr[i] - 'A']) { coins[arr[i] - 'A'] = -1; } if(1 == coins[arr[i] - 'A']) { coins[arr[i] - 'A'] = 0; } } } void MarkHeavyCoins(char arr[], int len) { int i; for(i = 0; i < len; i++) { if(2 == coins[arr[i] - 'A']) { coins[arr[i] - 'A'] = 1; } if(-1 == coins[arr[i] - 'A']) { coins[arr[i] - 'A'] = 0; } } } void MarkRestCoinsTrue(char a[], char b[], int len) { int x[COINS_MAXN]; memset(x, 0, sizeof(x)); int i; for(i = 0; i < len; i++) { x[a[i] - 'A'] = 1; x[b[i] - 'A'] = 1; } for(i = 0; i < COINS_MAXN; i++) { if(x[i] != 1) { coins[i] = 0; } } }