一、递归
递归是一种非常有效的问题求解方法,递归把一个问题分解成几个小的子问题,通过求解相同问题的更小实例来求解问题。
递归方法的特点:
- 递归方法调用方法自身;
- 每次的递归调用解决一个性质相同,但规模小一些的问题;
- 对基本事件的测试使递归调用结束;
- 最终,更小的子问题之一必是基本事件。
构造递归解决方案要考虑的4个问题:
- 如何使用相同类型的更小问题定义问题;
- 每次递归调用如何减小问题的规模;
- 问题的什么实例可以作为基本事件;
- 随着问题规模逐步变小,能否到达基本事件。
二、汉诺塔
问题描述:n个盘子和3根柱子:A(源)、B(目的)、C(备用),盘子的大小不同且中间有一孔,可以将盘子“串”在柱子上,每个盘子只能放在比它大的盘子上面。起初,所有盘子在A柱上,问题是将盘子一个一个地从A柱子移动到B柱子。移动过程中,可以使用C柱,但盘子也只能放在比它大的盘子上面。
递归的解决方法:问题简化
1、忽略最底下的那个盘子,解决n-1个盘子问题,但稍加修改,即C柱为目的,B柱是备用;
2、完成这一步后,n-1个盘子在C柱上,而最大的盘子仍留在A柱子上。这样,把最大的盘子从A柱移到B上,解决n=1的问题;
3、现在,所有你必须做的事情是把n-1个盘子从C柱移到B柱上,即:解决用C柱作为源柱,B柱作目的柱,A柱作备用柱的问题;
问题建模:
设towers(count, source, destination, spare)表示从source柱上移动count个盘子到dasetination柱,用spare做备用柱的问题。问题重新表述如下:
开始时,A柱上有n个盘子,B柱和C柱上没有盘,求解towers(n,A,B,C)。递归的解决方案陈述如下:
第一步:从初始状态开始,求解问题:towers(n-1,A,C,B),即忽略底部(最大)的盘子,并将最上面的n-1个盘子从A柱移到C柱上,使B柱备用,完成时,最大的盘子留在A柱上,所有其它盘子在C柱上。
第二步:现在,最大盘子在A柱上,所有其它盘子在C柱上,求解问题:towers(1,A,B,C),也就是将最大的盘子从A移到B上。因为这个盘子比已在C柱上的盘子大,所以不需要使用备用柱。这种基本事件不需要使用备用柱子。完成后,最大盘子在B柱上,而其他盘子仍在C柱上。
第三步:最后,当最大的盘子在B柱上而其他盘子在C柱上时,求解问题:towers(n-1,C,B,A),即,将n-1个盘子从C移动到B柱上,A柱备用。因为目的柱B上已经有一个最大的盘子,所以我们尅忽略它。完成后,就解决了原问题:所有的盘子都在B柱上。
Java解决方法代码:
输出结果:
count= 4
count= 3
count= 2
count= 1
Move top disk from pole A to pole C
count= 1
Move top disk from pole A to pole B
count= 1
Move top disk from pole C to pole B
count= 1
Move top disk from pole A to pole C
count= 2
count= 1
Move top disk from pole B to pole A
count= 1
Move top disk from pole B to pole C
count= 1
Move top disk from pole A to pole C
count= 1
Move top disk from pole A to pole B
count= 3
count= 2
count= 1
Move top disk from pole C to pole B
count= 1
Move top disk from pole C to pole A
count= 1
Move top disk from pole B to pole A
count= 1
Move top disk from pole C to pole B
count= 2
count= 1
Move top disk from pole A to pole C
count= 1
Move top disk from pole A to pole B
count= 1
Move top disk from pole C to pole B