3_寻找假币问题(分治法)
2015-09-10 21:30
190 查看
题目
一个袋子里有30个银币,其中一枚是假币,并且假币和真币一模一样,肉眼很难分辨,目前只知道假币比真币重量轻一点。请问,如何区分出假币?
分析
首先,分析一下寻找假币问题,采用递归分治的思想求解。首先为每个银币编号,然后将所有的银币等分为两份,放在天平的两边。这样就将区分30个银币的问题变为区别两堆银币的问题。
因为假币分量较轻,因此天平较轻的一侧中一定包含假币。
再将较轻的一侧中银币等分为两份,重复上述做法。
直到剩下两枚银币,便可用天平直接找出假银币。
分治算法思想
分治算法的基本思想是将一个计算复杂的问题分为若干个规模较小、计算简单的小问题来进行求解,然后综合各个小问题,得到最终问题的答案。执行过程如下:
对于一个规模为N的问题,若该问题可以容易的解决(比如说规模N较小),则直接解决,否则执行下面的步骤;
将该问题分解为M个规模较小的子问题,这些子问题应该互相独立,并且与原问题形式相同;
递归求解各个子问题;
然后将各个子问题的解合并得到原问题的解;
使用分治算法要求待求解的问题能够化简为若干个小规模的相同问题,通过逐步划分,达到一个易于求解的阶段而直接进行求解。然后再程序中使用递归算法进行求解。
代码
#include <iostream> #include <cstdlib> using namespace std; const int MAXNUM = 30; int falseCoin(int weight[], int lhs, int rhs) { if (lhs == rhs) return lhs + 1; //如果只剩下两个银币,则较轻的那个便是假币 else if (lhs == (rhs - 1)) { return weight[lhs] < weight[rhs] ? lhs + 1 : rhs + 1; } int lsum = 0, rsum = 0; //如果偶数个银币,则比较两等份 if ((rhs - lhs + 1) % 2 == 0) { for (int i = lhs; i < (lhs + (rhs - lhs + 1) / 2); i++) { lsum += weight[i]; } for (int j = lhs + (rhs - lhs + 1) / 2; j <= rhs; j++) { rsum += weight[j]; } //左右两份等重,则无假币 if (lsum == rsum) return -1; else return (lsum < rsum) ? falseCoin(weight, lhs, lhs + (rhs - lhs) / 2) : falseCoin(weight, lhs + (rhs - lhs) / 2 + 1, rhs); } //如果奇数个银币,则比较除中间银币外的两等份 else if ((rhs - lhs + 1) % 2 != 0) { for (int i = lhs; i < (lhs + (rhs - lhs) / 2); i++) { lsum += weight[i]; } for (int j = (lhs + (rhs - lhs) / 2 + 1); j <= rhs; j++) { rsum += weight[j]; } //左右两份等重,则无假币 if (lsum == rsum && weight[lhs] == weight[lhs + (rhs - lhs) / 2]) return -1; //如果两份等重,中间银币较轻,则中间银币为假币 else if (lsum == rsum && weight[lhs] > weight[lhs + (rhs - lhs) / 2]) return lhs + (rhs - lhs) / 2 + 1; //否则,返回较轻那份中的假币 else return (lsum < rsum) ? falseCoin(weight, lhs, lhs + (rhs - lhs) / 2 - 1) : falseCoin(weight, lhs + (rhs - lhs) / 2 + 1, rhs); } } int main() { int weight[MAXNUM]; int n; while (cin >> n) { for (int i = 0; i < n; i++) cin >> weight[i]; int falsePos = falseCoin(weight, 0, n - 1); if (falsePos != -1) cout << "第" << falsePos << "个银币为假币!" << endl; else cout << "无假币!" << endl; }//while system("pause"); return 0; }
GitHub代码下载
相关文章推荐
- Rust and Go
- 使用事件驱动模型实现高效稳定的网络服务器程序
- POJ 3113 Manhattan Wiring(插头DP)
- 白话空间统计十六:增量空间自相关
- N排列盒子涂色方法总和 DP SRM 666 div1 medium SumOverPermutations
- 0909 第一次上机
- iOS简易柱状图(带动画)--新手入门篇
- 密码学的对称加密和不对称加密有哪些和各自特点
- struct 中的宏定义--没有作用域,只是为了逻辑上理解,和放在外部是一样的
- 读《大学之路》有感
- java设计模式系列--简单工厂模式
- 处理FTP上传成功推理
- 【iOS】iOS viewDidLoad 方法名问题
- Java学习之字符串的创建
- openfire创建插件
- hdu 5344 MZL's xor(数学之异或)
- POJ 1236 Network of Schools(强连通分量缩点)
- xml有哪些解析技术?区别是什么?
- HTML 元素
- ajax