题目链接:

POJ 1013   http://poj.org/problem?id=1013

百炼  假币问题  http://bailian.openjudge.cn/practice/2692/

题目大意

有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.

解题思路

第一种代码

每一枚硬币有三种状态:较重的假币、较轻的假币、真硬币。

由于只有一枚假币,且总共只有12枚硬币,因此可以把所有硬币的所有状态都枚举一遍对每一种假设的情况进行验证:若是某种假设符合输入的三个条件,那么该假设就是成立的。

  1. #include<stdio.h>
  2. int status[]={};//表示12枚硬币的真假状态:0为真,-1为假币且假币较轻,1为假币且假币较重
  3. char left[][],right[][],result[][];
  4. bool Balanced();//判断某种假设是否合理
  5. int main()
  6. {
  7. int i,num;
  8. scanf("%d",&num);
  9. while(num--)
  10. {
  11. for(i=;i<;i++)
  12. scanf("%s %s %s",left[i],right[i],result[i]);
  13. for(i=;i<;i++) status[i]=;//开始的时候,假设全部硬币都是真硬币。
  14. for(i=;i<;i++)
  15. {
  16. status[i]=;//假设第i枚硬币是假币且假币较重
  17. if(Balanced())//检验该种假设是否合理
  18. break; //若合理则已经得到答案,结束循环
  19.  
  20. status[i]=-;//假设第i枚硬币是假币且假币较轻
  21. if(Balanced())//检验该种假设是否合理
  22. break; //若合理则已经得到答案,结束循环
  23.  
  24. status[i]=;//上述两种假设都不合理的话,第i枚硬币为真硬币。
  25. }
  26.  
  27. printf("%c is the counterfeit coin and it is %s.\n",i+'A',status[i]==?"heavy":"light");
  28. /**/
  29. }
  30.  
  31. return ;
  32. }
  33.  
  34. bool Balanced()//判断某种假设是否合理:合理则返回true,否则返回false.
  35. {
  36. int i,k,leftW,rightW;
  37. for(i=;i<;i++)//依次检验三条规则
  38. {
  39. leftW=rightW=;
  40. for(k=;left[i][k]!='\0';k++)
  41. {
  42. leftW+=status[left[i][k]-'A'];
  43. rightW+=status[right[i][k]-'A'];
  44. }
  45. if(leftW>rightW&&result[i][]!='u') return false;
  46. if(leftW==rightW&&result[i][]!='e') return false;
  47. if(leftW<rightW&&result[i][]!='d') return false;
  48. }
  49. return true;
  50. }

来自刘家瑛《算法基础与在线实践》

第二个代码

来源:北大郭炜老师。道理都一样,只是上面那段代码理解起来似乎比较好理解一点。

对于每一枚硬币先假设它是轻的,看这样是否符合称量结果。如果符合,问题即解决。如果不符合,就假设它是重的,看是否符合称量结果。

把所有硬币都试一遍,一定能找到特殊硬币。

  1. #include <iostream>
  2. #include <cstring>
  3. using namespace std;
  4. char Left[][]; //天平左边硬币
  5. char Right[][]; //天平右边硬币
  6. char result[][]; //称量结果
  7. bool IsFake(char c,bool light);//light为真表示假设假币为轻,否则表示假设假币为重
  8. int main()
  9. {
  10. int t;
  11. cin >> t;
  12. while(t--)
  13. {
  14. for(int i = ;i < ; ++i) cin >> Left[i] >> Right[i] >> result[i];
  15. for(char c='A'; c<='L';c++)
  16. {
  17. if( IsFake(c,true) )//假设c这个硬币为假硬币而且它比真硬币轻
  18. {
  19. cout << c << " is the counterfeit coin and it is light.\n";
  20. break;
  21. }
  22. else if( IsFake(c,false) )//假设c这个硬币为假硬币而且它比真硬币重
  23. {
  24. cout << c << " is the counterfeit coin and it is heavy.\n";
  25. break;
  26. }
  27. }
  28. }
  29. return ;
  30. }
  31. bool IsFake(char c,bool light)//light 为真表示假设假币为轻,否则表示假设假币为重
  32. {
  33. for(int i = ;i < ; ++i)
  34. {
  35. char * pLeft,*pRight; //指向天平两边的字符串
  36. if(light)
  37. {
  38. pLeft = Left[i];
  39. pRight = Right[i];
  40. }
  41. else
  42. {
  43. pLeft = Right[i];
  44. pRight = Left[i];
  45. }
  46.  
  47. switch(result[i][])
  48. {
  49. case 'u':
  50. if ( strchr(pRight,c) == NULL) return false;
  51. break;
  52. case 'e':
  53. if( strchr(pLeft,c) || strchr(pRight,c)) return false;
  54. break;
  55. case 'd':
  56. if ( strchr(pLeft,c) == NULL) return false;
  57. break;
  58. }
  59. }
  60. return true;
  61. }

POJ1013 称硬币的更多相关文章

  1. POJ1013称硬币【枚举】

    Counterfeit Dollar Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 52474   Accepted: 16 ...

  2. 枚举-称硬币POJ1013

    #include <iostream> #include<string.h> using namespace std; char Lleft[][]; char Lright[ ...

  3. 算法题----称硬币: 2n(并不要求n是2的幂次方)个硬币,有两个硬币重量为m+1, m-1, 其余都是m 分治 O(lgn)找出假币

    Description: 有2n个硬币和一个天平,其中有一个质量是m+1, 另一个硬币质量为m-1, 其余的硬币质量都是m. 要求:O(lgn)时间找出两枚假币 注意: n不一定是2的幂次方 算法1: ...

  4. C++基础算法学习——猜假币

    有12枚硬币.其中有11枚真币和1枚假币.假币和真币重量不同,但不知道假币比真币轻还是重.现在,用一架天平称了这些币三次,告诉你称的结果,请你找出假币并且确定假币是轻是重(数据保证一定能找出来).例题 ...

  5. ACM训练计划建议(写给本校acmer,欢迎围观和指正)

    ACM训练计划建议 From:freecode#  Date:2015/5/20 前言: 老师要我们整理一份训练计划给下一届的学弟学妹们,整理出来了,费了不少笔墨,就也将它放到博客园上供大家参考. 菜 ...

  6. 【POJ水题完成表】

    题目 完成情况 poj1000:A+B problem 完成 poj1002:电话上按键对应着数字.现在给n个电话,求排序.相同的归一类 完成 poj1003:求最小的n让1+1/2+1/3+...+ ...

  7. ACM训练计划建议(转)

    ACM训练计划建议 From:freecode#  Date:2015/5/20 前言: 老师要我们整理一份训练计划给下一届的学弟学妹们,整理出来了,费了不少笔墨,就也将它放到博客园上供大家参考. 菜 ...

  8. (BruteForce)暴力破解经典题目总结

    在算法竞赛中,很多问题是来不及用数学公式推导出来的.或者说根本就找不到数学规律,这时我们就需要使用枚举来暴力破解. 不过枚举也是需要脑子的,一味的暴力只能超时.因此我这里选择了几道mooc上经典的题目 ...

  9. codes often WA

    枚举: 1.完美立方 #include<iostream> #include <cstdio> using namespace std; int main() { int N; ...

随机推荐

  1. uva 10344 23 out of 5 凑运算结果 全排列+dfs

    五个数三个运算符号,排列之后凑成结果为23,不考虑优先级. 很水,数据量也不大,先生成五个数的全排列,用dfs找出结果能否为23即可. 代码: #include <cstdio> #inc ...

  2. 迭代器模式(Iterator)

    @@@模式定义: 提供一种方法顺序访问一个聚合对象中的各个元素,而又不需暴露该对象的内部表示. @@@练习示例:  工资表数据的整合 @@@示例代码: \pattern\PayModel.java ~ ...

  3. 计算机中的概念: 视图 VS 镜像

    这两个概念还是不太一样的.下面来说说个人的理解,记录一下. 1. 镜像 镜像可以理解为一份完全一样的拷贝.也就是"深度拷贝",一个复制品. 比如 iso映像文件,ubuntu-12 ...

  4. LeetCode 总结

    LeetCode 方法详解

  5. Kudu-java数据库简单操作

    参考官网:http://kudu.apache.org/docs/kudu_impala_integration.html 参考:https://my.oschina.net/weiqingbin/b ...

  6. MySQL在线大表DDL操作 (转)

    http://www.cnblogs.com/janehoo/p/5382474.html 线大表DDL操作的方法: 1.主从架构轮询修改 需要注意: a.主库会话级别的记录binglog的参数关闭 ...

  7. __attribute__中constructor和destructor[总结]

    1.前言 最近看到一份代码,看到一个函数前面用__attribute__((destructor))修饰,当时感觉有点怪怪的,搜了整个程序,也没发现哪个地方调用这个函数.于是从字面意思猜想,该函数会在 ...

  8. php5.6 的interactive模式

    1. 发现运行php 的interactive shell 的时候,不能输入一行执行一行,而要 输入完一整段内容,再按  ctrl + d才能执行这段内容. 原因是,没安装 readline这个模块, ...

  9. 解决excel日期变成数字的问题

    在Excel中如果单元格的公式是日期格式,那么引用后的数值是错误的[不是日期格式而被转换成数字类型了],这种情况显然不是我们想要的结果 解决办法: 在公式中强制转成文本类型即可(="Date ...

  10. memcache的资料集

    1. 安装与查看过程(完整) https://www.cyberciti.biz/faq/rhel-fedora-linux-install-memcached-caching-system-rpm/ ...