这是个很经典的问题,但是我看了很多讲解都感觉不是很系统,但是受到了看的讲解的启发,在这里希望写一个比较严谨系统的讲解。
题目是这样的:在漆黑的夜里,四位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,四个人一共只带了一只手电筒,而桥窄得只够让两个人同时通过。如果各自单独过桥的话,四人所需要的时间分别是1,2,5,10分钟;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,你如何设计一个方案,让用的时间最少。(17分钟)
这个问题实际上可以抽象为更一般的问题:N个人过桥,每人需要的时间是t[i],过桥规则不变,求所有人过桥所用的最短时间。
大多数题解是直接写,选两个最快的人,两个最慢的人,然后什么情况选什么方式过桥,然后递归。这样其实缺少理论上的严谨性。很多人会问:为什么选这四个人啊?
好,下面我们就来严谨的分析一下。
首先,下面几句话是显然的:
1.每个人都需要过桥;
2.最慢的两个人过桥后永远不会回来;(因为不会有人需要他们帮着过桥,也不会需要他们送手电筒,当然默认N>=4以保证最慢和最快不重合)
3.最慢的两个人不能在对面没有人而这边还有人的情况下两个人一起过桥;(否则就违反了第二条,必须有一个人回来送手电筒)
好,有了上面三句话,我们很容易得到两个推论。
1.要考虑把N个人送过去的最优时间,只需要先考虑怎么把最慢的两个人先送过去的最优时间。(类似于动态规划中的无后效性);
2.既然最慢的两个人不能独自过桥,那必须需要别人的帮助。那么需要谁的帮助呢?显然是最快的人的帮助。最快的几个人呢?讨论呗。(但是可以证明最多不超过两个人,因为假设有第三个人,任何一步他的帮助都没有什么作用)
这样,我们就已经知道为什么要选出这四个人了。现在来分析最优方案。
假设,t[1]~t[N] 是从小到大排好序的。设 A=t[1],B=t[2],C=t[N-1],D=t[N].
现在开始讨论:
1.如果C,D需要一个人的帮助过桥。那么最好的方案肯定是A把C送过去,A回来,A把D送过去,A回来。(A必须要回来,因为这边至少还有个B吧~)
T1=C+A+D+A
2.如果C,D需要两个人的帮助过桥。那么最好的方案肯定是A把B送过去,A回来,C和D过去,B回来。(B必须要回来,因为这边至少还有个A吧~)
T2=B+A+D+B
所以,只需要比较T1和T2的大小就可以确定选择哪一个方案。由公式,显然只需要比较A+C和2*B的大小。
而且,这两个方案的初始状态和终止状态都是一样的,而且选择之后的效果都是,左边的人少了两个。
那么问题就自然的转化为了N-2个人的过桥问题。就是递归的思想。
下面分析一下边界。
如果有三个人A,B,C(由小到大)。显然是用A送C,A回来,A送B。时间T=A+B+C。
如果有两个人。时间就是最大的时间。
一个人。时间就是这个人的时间。
算法详解就到这里。代码可以从网上就可以搜到,可以看一下是不是能看懂了呢?