昨天下午上课之前有朋友在QQ群里发了一个问题,
初看题目,很像汉诺塔问题,都是要将一段按次序排列的数字倒序排列.
那么首先来看下汉诺塔问题:
///
上帝创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上安大小顺序摞着64片黄金圆盘。 上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘。
///
假设三根柱子分别为x,y,z,圆盘原来全部在x上,需要移动到y上,z可以做零时跳板
那么,解题思路大致如下:
首先,假设只有一个圆盘,那么很好办,直接将圆盘从x移动到y就可以了.但是如果不止一个盘子呢?
从整体来考虑,假设有n个圆盘,解决问题的最后一步应该是,将第n个盘从x移动到y,然后将在z上的其他n-1个圆盘移动到y.那么在这一步之前就是将n-1个盘从x移动到z然后将前面的(n-1)-1个盘从y移动到z.再继续往前推,很容易发现这样一个递归过程,那就是:
在移动时,总是将最大的一个从x移动到y或者是z,而将之前的从y或z上移动到x,那么怎么来确定最大的盘到底是从x移动到y还是z呢?
很明显,如果y上面已经放了一个按顺序放置的序列,而z为空时,就应该将盘子放在z上,反之,z上有这样的序列就放在y上.
那么这个递归到什么时候结束呢?那就是x上只剩下最后一个盘子了,那么就直接把盘子移动到y.
基于以上分析,用c语言实现汉诺塔问题的代码如下:
//n是盘子个数,,圆盘原来全部在x上,需要移动到y上,z可以做零时跳板
void move(unsigned int x, unsigned int y)
{
printf("%d->%d/n", x, y);
}
void TowersOfHanoi(int n, int x, int y, int z)
{
if (n > 0)
{
TowersOfHanoi(n-1, x, z, y);
move(x,y);
TowersOfHanoi(n-1, z, y, x);
}
}
由上面解法,可以得到一般递归问题的解决思路:
首先,整体考虑问题,放弃细节,逆向思考,找到递归问题的入口,找出递归规律
其次,确定递归返回点
最后,注意递归问题的出口,也就是递归结束条件
那么,我们来分析下火车头的问题,首先,需要将车头顺序倒过来的话我们可以假设,如果所有的车头按序号从小到大在c段停放的话,只需要将车头开到a段就可以了,那么如何让车头这样停到c上呢?这就是一个典型的 汉诺塔问题模型了.那么依照上面的例子来写程序:
void move(unsigned int a, unsigned int c)
{
printf("%d->%d/n", a, c);
}
void test(int n, int a, int b, int c)
{
if (n > 0)
{
test(n-1, a, b, c);
move(a,c);
test(n-1, b, c, a);
}
}
void main()
{
int n;
int a=1,b=2,c=3;
scanf("%d",&n);
test(n,a,b,c);
while(n) //次循环用来做将车头从c到a的模拟
{
move(c,a);
n--;
}
}