简介
今天给大家介绍一个很经典的减治法解决假币问题的方法,改方法引自最优化算法一书。
问题:假币问题
在n枚外观相同的硬币中,有一枚是假币,并且已知假币较轻。可以通过一架天平来任意比较两组硬币,从而得知两组硬币的重量是否相同,或者哪一组更轻一些,假币问题(base coin problem)要求设计一个高效的算法来检测出这枚假币。
想法
解决假币问题的最自然的想法就是一分为二,也就是把n枚硬币分成两组,每组有n/2枚硬币,如果n为奇数,就留下一枚硬币,然后把两组硬币分别放到天平的两端。如果两组硬币的重量相同,那么留下的硬币就是假币;否则,用同样的方法对较轻的那组硬币进行同样的处理,因为假币一定在较轻的那组里。
在假币问题中,尽管我们把硬币分成了两组,但每次用天平比较后,只需解决一个规模减半的问题,所以,它属于一个间质减治算法。该算法在最坏情况下满足如下递推式:
- T(n) = 0 当 n = 1 时
- T(n) = T(n/2) + 1 当 n > 1 时
应用扩展递归技术求解这个递推式,得到T(n) = O(log<sub>2</sub>n)。
对于假币问题,将问题规模减半的算法很容易想到,但实际上,减半不是一个最好的选择,考虑不是把硬币分成两组,而是分成三组,前两组有[n/3]组硬币,其余的硬币作为第三组,将前两组硬币放到天平上,如果它们的重量不同,则假币一定在第三组中,用同样的方法对第三组进行处理;如果前两组的重量不同,则假币一定在较轻的一组中,用同样的方法对较轻的那组硬币进行处理。显然这个算法满足如下递推式:
- T(n) = 0 当 n = 1 时
- T(n) = T(n/3) + 1 当 n > 1 时
这个递推式的解是T(n) = O(log<sub>3</sub>n),将原问题一分为三从而获得了更少的比较次数。
算法
采用递归技术设计假币问题的算法,设计函数Coin实现假币问题,算法用伪代码描述如下:
假币问题Coin
输入:硬币所在数组的下标范围low和high,硬币的个数n
输出:假币在硬币集合中的序号
1. 如果n等于1,则该硬币即为假币,输出对应的序号,算法结束;
2. 计算3组的硬币个数num1、num2和num3;
3. add1=第一组硬币的重量和;add2=第二组硬币的重量和;
4. 根据情况执行下述三种操作之一:
4.1 如果add1大于add2,则在第一组硬币中查找;
4.2 如果add1大于add2,则在第二组硬币中查找;
4.3 如果add1等于add2,则在第三组硬币中查找。
寄语
今天也是小落叶复习考试的一天,时间有限只能初步的给大家介绍有关假币问题,这一经典的减治算法。希望可以对大家有所帮助。