1、飞机飞行问题
每个飞机只有一个油箱,飞机之间可以相互加油(注意是相互,没有加油机),一箱油可供一架飞机绕地球飞半圈。
问:为使至少一架飞机绕地球一圈回到起飞时的飞机场,至少需要出动几架飞机? (所有飞机从同一机场起飞,而且必须安全返回机场,不允许中途降落,中间没有飞机场)
解答:
我们把全程划分为多个4分之1段,可以知道,要一架飞机全程需要两箱油,假设飞机A为需要全程的飞机,则在4分之1时油必须满箱,由此考虑过程:
ABC同时起飞,至8分之1时,C给AB各4分之1的油,剩下4分之1油返回,AB继续飞行到4分之1时,B给A加4分之1油,将A加满,B剩余2分之1油,返回。
A飞至2分之1时,D反方向起飞,至4分之3时,D给A加4分之1油,E反方向飞,到8分之1的位置,给AD各4分之1的油,ADE同时返回。
注:此方法为最优解,其余加油方式均不能满足。
2、100层楼扔玻璃球,鸡蛋或者杯子的问题
某幢大楼有100层。你手里有两颗一模一样的玻璃珠。
当你拿着玻璃珠在某一层往下扔的时候,一定会有两个结果,玻璃珠碎了或者没碎。这幢大楼有个临界楼层。低于它的楼层,往下扔玻璃珠,玻璃珠不会碎,等于或高于它的楼层,扔下玻璃珠,玻璃珠一定会碎。
玻璃珠碎了就不能再扔。现在让你设计一种方式,使得在该方式下,最坏的情况扔的次数比其他任何方式最坏的次数都少。也就是设计一种最有效的方式。
例如:有这样一种方式,第一次选择在60层扔,若碎了,说明临界点在60层及以下楼层,这时只有一颗珠子,剩下的只能是从第一层,一层一层往上实验,最坏的情况,要实验59次,加上之前的第一次,一共60次。
若没碎,则只要从61层往上试即可,最多只要试40次,加上之前一共需41次。两种情况取最多的那种。故这种方式最坏的情况要试60次。
那该如何设计方式呢?
解答:
如果碎了的话,就不能再继续用了。
如果我从x楼扔下,没碎,在x+1楼扔下,碎掉了,即证明找到了x+1是刚好碎掉的楼层。
问题的关键是,怎么快速找到这个楼层呢?这是一个查找问题。
我们需要一个策略方法来快速地找到它,就看谁的方法比较优秀。
而优秀的方法其评价标准显而易见:各种情况下都能快速地找到目标楼层。
思考路径:
如果只有一个玻璃珠的话,应该怎么做呢?
稍微想一下也可以知道,必定只能一层一层地扔,1楼没碎扔2楼,2楼没碎扔3楼,直到碎掉。
现在我有两个玻璃珠。
学习过算法和程序的人应该都知道二分法,很容易想到这样去做,因为面对的是一个搜索问题。
所以可能会给出这样的策略:
从50楼扔下,没碎的话,再扔75楼,再没碎我扔88楼,依次下去很快就可以锁定楼层?
很快你会意识到问题所在,万一第一次从50层楼扔下去,碎了咋整,难道又一层一层地扔?
玻璃珠刚好在49层碎掉的话。最差的情况我需要扔50次,这方法不行。
再一个比较常见的方法是,先分区间的扔,再慢慢地一层一层地扔,隐含着分段查找的策略。
===============================================================================================================================
具体操作方式是:
先从第10楼扔,再从第20楼扔,依次下去,如果到某一层碎掉,比如50层碎掉了,我再从41楼开始扔,这样的话应该算是比较快了把?
这个方法是要快一点,不过如果玻璃珠在99楼才会刚好碎掉。这样,最差的情况下,需要扔19次才能找到目标楼层。
我们需要的方法是玻璃珠不论是在1楼碎,49楼碎,99楼碎都要能快速锁定的方法。
继续思考刚才方法的缺陷,当玻璃珠质量比较差的时候,此方法还是比较快速的找到的。比如玻璃珠是在19楼刚好碎,我只需要扔11次,比99楼刚好碎的情况要少很多次。
所以我们的愿望是:
玻璃珠的质量无论分布在哪个查找区间,都可以快速地找到。所以我们可以“匀”一下刚才的方法。即最开始需要大胆地扔,然后再慢慢小心地扔。
具体方法设计:
每次扔的区间减少一层,这样做可以保证每个区间查找的最差次数是一样的。
假定第一步在15楼扔,没碎的话则下一步在29楼扔,没碎下一步在42楼扔....碎掉之后则在上一次没碎的楼层开始向上扔。那么最开始在哪一层开始扔呢??
这里我们需要拿支笔算一下:
x+(x-1)+(x-2)+...+2 >=100
求解出答案为14。
即最终给出的解决方案是:
最开始从14楼开始扔,没碎的话在27楼扔,再没碎的话在39楼扔.....一旦碎掉,则从上一次没碎的楼层逐层往上扔,即可快速确认杯子在哪一层刚好会碎掉。
3、5赛道25匹马,找最快的5匹的问题
一共有25匹马,有一个赛场,赛场有5个赛道,就是说最多同时可以有5匹马一起比赛。假设每匹马都跑的很稳定,不用任何其他工具,只通过马与马之间的比赛,试问,最少得比多少场才能知道跑得最快的5匹马?(不能使用撞大运的算法)
解答:目前网上最典型的算法认为是10次
(1) 首先将25匹马分成5组,并分别进行5场比赛之后得到的名次排列如下:
A组: [A1 A2 A3 A4 A5]
B组: [B1 B2 B3 B4 B5]
C组: [C1 C2 C3 C4 C5]
D组: [D1 D2 D3 D4 D5]
E组: [E1 E2 E3 E4 E5]
其中,每个小组最快的马为[A1、B1、C1、D1、E1]。
(2) 将[A1、B1、C1、D1、E1]进行第6场,选出第1名的马,不妨设 A1>B1>C1>D1>E1.
此时第1名的马为A1。
(3) 将[A2、B1、C1、D1、E1]进行第7场,此时选择出来的必定是第2名的马,不妨假设为B1。因为这5匹马是除去A1之外每个小组当前最快的马。
(3) 进行第8场,选择[A2、B2、C1、D1、E1]角逐出第3名的马。
(4) 依次类推,第9,10场可以分别决出第4,5名的吗。
因此,依照这种竞标赛排序思想,需要10场比赛是一定可以取出前5名的。