5 Drease-and-Conquer Fake-Coin Problem(减治法求假币问题)
2015-07-02 23:08
966 查看
减治法Decrease and Conquer
*Exploring the relationship between a solution to a given instance of (e.g., P(n) )a problem and a solution to a smaller instance (e.g., P(n/2) or P(n-1) )of the same problem.*Use top down(recursive) or bottom up (iterative) to solve the problem.
减治法举例Examples of Decrease and Conquer
Decrease by a constant:the size of the problem is reduced by the same constant on each iteration/recursion of the algorithm.减去一个常量
Insertion sort
Graph search algorithms:
DFS
BFS
Algorithms for generating permutations, subsets
Decrease by a constant factor:the size of the problem is reduced by the same constant factor on each iteration/recursion of the algorithm.
减去一个常量因子
Binary search
Fake-coin problems
Variable-size decrease:the size reduction pattern varies from one iteration of an algorithm to another.
减去一个可变规模
Euclid’s algorithm
Fake-coin problems:
问题描述:
在n枚外观相同的硬币中,有一枚是假币,并且已知假币较轻。可以通过一架天平来任意比较两组硬币,从而得知两组硬币的重量是否相同,或者哪一组更轻一些,但不知道轻多少,假币问题是要求设计一个高效的算法来检测出这枚假币。理解问题:
问题的解决是经过一系列比较和判断,可以用判定树来描述这个判定过程。设计算法
解决这个问题的最自然的想法就是一分为二,也就是把硬币分成两组。把n枚硬币分成两组,每组有 枚硬币,如果n为奇数,就留下一枚硬币,然后把两组硬币分别放到天平的两端。如果两组硬币的重量相同,那么留下的硬币就是假币;否则,用同样的方法对较轻的那组硬币进行同样的处理,假币一定在较轻的那组里。
考虑不是把硬币分成两组,而是分成三组,前两组有n/3 组硬币,其余的硬币作为第三组,将前两组硬币放到天平上,如果他们的重量相同,则假币一定在第三组中,用同样的方法对第三组进行处理;如果前两组的重量不同,则假币一定在较轻的那一组中,用同样的方法对较轻的那组硬币进行处理。
分析算法
1、用减治法(减半)
把n个硬币分为两堆,每堆n/2个,每次称一堆。易见 W(1)=0
W(n)=W(n/2)+1
解得 W(n)= log2n
T(n)=O(log2n)。
2、用减治法(减n/3)
把n个硬币分为三堆,每堆n/3个,每次称任意二堆。易见 W(1)=0
W(n)=W(n/3)+1
解得 W(n)= log3n
T(n)=O(log3n)
结果比减半法更好。
代码实现
1、减半
//求n个硬币中的一个假币//输入:N 个硬币,假设一个假币比其它轻,
//输出:指出假币
FCR(a(n))
{
If n 是奇数,则取出一个硬币a1;
称重a1----a(n/2)和a(n/2+1)-----a(n)得weigh1 和weigh2;
If 重量相等,返回a1为假币;
Else if weigh1 >weigh2
FCR(a(n/2+1)-----a(n) );
if weigh1 < weigh2
FCR(a2----a(n/2));
}
2、减n/3
//求n个硬币中的一个假币//输入:N 个硬币,假设一个假币比其它轻,
//输出:指出假币
#include <stdio.h> int Coin(int a[],int low,int high,int n) { int num1,num2,num3,i; int add1=0,add2=0; if(n==1) { return low+1; } if(n%3==0) { num1=num2=n/3; } else { num1=num2=n/3+1; } num3=n-num1-num2; for(i=0;i<num1;i++) { add1=add1+a[low+i]; } for(i=num1;i<num1+num2;i++) { add2=add2+a[low+i]; } if(add1<add2) { return Coin(a,low,low+num1-1,num1); } else if(add1>add2) { return Coin(a,low+num1-1,low+num1+num2-1,num2); } else { return Coin(a,low+num1+num2,high,num3); } } int main() { int a[100]; int i,n,low,high,address; printf("Please input the counts of the coins:\n"); scanf("%d",&n); low = 0; high = n-1; printf("Please input the weight of every coin: \n"); for(i=0; i<n; ++i) { scanf("%d",&a[i]); } address=Coin(a,low,high,n); printf("The fake coin is %dnd\n",address+1); return 0; }
拓展(纯拷贝老师的PPT):
1、不知道假币与真币相比较轻还是较重。
设有八枚硬币,分别表示为a,b,c,d,e,f,g,h,从八枚硬币中任取六枚a,b,c,d,e,f,在天平两端各放三枚进行比较。假设a,b,c三枚放在天平的一端,d,e,f三枚放在天平的另一端,可能出现三种比较结果:⑴ a+b+c>d+e+f
⑵ a+b+c=d+e+f
⑶ a+b+c<d+e+f
若a+b+c>d+e+f,可以肯定这六枚硬币中必有一枚为假币,同时也说明g,h为真币。这时可将天平两端各去掉一枚硬币,假设去掉c和f,同时将天平两端的硬币各换一枚,假设硬币b,e作了互换,然后进行第二次比较,比较的结果同样可能有三种:
① a+e>d+b:这种情况表明天平两端去掉硬币c,f且硬币b,e互换后,天平两端的轻重关系保持不变,从而说明了假币必然是a,d中的一个,这时我们只要用一枚真币(例如h)和a进行比较,就能找出假币。若a>h,则a是较重的假币;若a=h,则d为较轻的假币;不可能出现a<h的情况。
② a+e=d+b:此时天平两端由不平衡变为平衡,表明假币一定在去掉的两枚硬币c,f中,同样用一枚真币(例如h)和c进行比较,若c>h,则c是较重的假币;若c=h,则f为较轻的假币;不可能出现c<h的情况。
③ a+e<d+b:此时表明由于两枚硬币b,e的对换,引起了两端轻重关系的改变,那么可以肯定b或e中有一枚是假币,同样用一枚真币(例如h)和b进行比较,若b>h,则b是较重的假币;若b=h,则e为较轻的假币;不可能出现b<h的情况。
[title3]2、扩展算法,使之能处理n枚硬币中有1枚假币的问题。[/title3]
相关文章推荐
- UIScrollView+UIPageControl实现图片分页
- LeetCode_Disjoint-Set_Longest Consecutive Sequence
- UI基础:视图控制器.屏幕旋转.MVC
- UI基础:视图控制器.屏幕旋转.MVC 分类: iOS学习-UI 2015-07-02 22:21 62人阅读 评论(0) 收藏
- IOS键盘的相关设置(UITextfield)
- IOS--UI--LessonUILabel
- IOS--UI--LessonButton UIImage
- IOS菜鸟的所感所思(十五)—— UIScrollView和UIPageControl的组合
- 快速的判断两个字符串型数组是否有交集
- iOS学习笔记 (9) UITabBarController分栏控制器
- Map存储 (key, value)
- iOS学习笔记(6)UINavigationController
- Android5.0L因SystemUI ANR导致的黑屏问题分析
- iOS学习笔记(4)UIView和UIImageView
- UIButton/按钮
- uCGUI 按键切换对话框内子控件焦点
- 3000套IOS android源码分享 7.2G UI素材
- 加班~~~第二天之自定义UIPageControl控件
- 【Web探索之旅】第三部分第三课:协议
- UVA 11235--Frequent values+RMQ问题