汉诺塔问题和青蛙跳台阶问题的递归解决

1.汉诺塔问题

汉诺塔问题是一个经典的问题。汉诺塔(Hanoi Tower),又称河内塔,源于印度一个古老传说。
大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。
大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。
并且规定,任何时候,在小圆盘上都不能放大圆盘,且在三根柱子之间一次只能移动一个圆盘。
问应该如何操作?

这个问题呢,想必大家也听过,那么怎么解决呢。首先我们先从简单的开始,从一个盘子,两个盘子,三个盘子去开始移动,来分析问题。
一下这个图是我粗略的画的,是分别移动1,2,3盘子的情形:
在这里插入图片描述
移动一个盘子:A-》C
移动两个盘子:A-》B A-》C B-》 C
移动三个盘子:A-》C A-》B C-》B A-》C B-》A B-》C A-》C
从中,在移动三个盘子的时候,我们来看,当最底下的盘子还在A,其他两个盘子在B时,可以把他看为是最上面两个盘子从A经过C移到了B,之后再把A上的盘子移到C,最后又可以把B上的两个盘子经过A移到了C,最后就移动成功了。由此,就可以把他用递归来解决了。代码如下:

public class TestDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();
        hanoi(n, 'A', 'B', 'C');
    }

    public static void move(char pos1, char pos3) {

        System.out.println(pos1 + "->" + pos3 + " ");
    }

    public static void hanoi(int n, char pos1, char pos2, char pos3) {
        if (n == 1) {
            move(pos1, pos3);
             return;
        }
        hanoi(n - 1, pos1, pos3, pos2);
        move(pos1, pos3);
        hanoi(n - 1, pos2, pos1, pos3);
    }
}

定义一个方法,只要有一个盘子,就把他从A移动到C,否则,就先把n-1个盘子先从A经过C移动到B,再把剩下的一个从A移动到C,最后再把n-1个盘子从B经过A移动到C。这里也就体现了递归的把大事化小的,分而治之的特点。n==1也就是递归的终止条件。
在这呢,我在给大家分享一个小故事,我也是从同学那看到的,希望对你们也有所帮助:

对递归的理解的要点主要在于放弃!放弃你对于理解和跟踪递归全程的企图,
只理解递归两层之间的交接,以及递归终结的条件。想象你来到某个热带丛
林,意外发现了十层之高的汉诺塔。正当你苦苦思索如何搬动它时,林中出
来一个土著,毛遂自荐要帮你搬塔。他名叫二傻,戴着一个草帽,草帽上有
一个2字,号称会把一到二号盘搬到任意柱。你灵机一动,问道:“你该不
会有个兄弟叫三傻吧?”“对对,老爷你咋知道的?他会搬一到三号盘。
“”那你去把他叫来,我不需要你了。“于是三傻来了,他也带着个草帽,
上面有个3字。你说:”三傻,你帮我把头三个盘子移到c柱吧。“三傻沉吟
了一会,走进树林,你听见他大叫:”二傻,出来帮我把头两个盘子搬到C!“
由于天气炎热你开始打瞌睡。朦胧中你没看见二傻是怎么工作的,二傻干完
以后,走入林中大叫一声:“老三,我干完了!”三傻出来,把三号盘从A搬到B
,然后又去叫二傻:“老二,帮我把头两个盘子搬回A!”余下的我就不多说了,
总之三傻其实只搬三号盘,其他叫二傻出来干。最后一步是三傻把三号盘搬到C,
然后呼叫二傻来把头两个盘子搬回C事情完了之后你把三傻叫来,
对他说:“其实你不知道怎么具体一步一步把三个盘子搬到C,是吧?”
三傻不解地说:“我不是把任务干完了?”你说:“可你其实叫你兄弟二
傻干了大部分工作呀?”三傻说:“我外包给他和你屁相干?”
你问到:“二傻是不是也外包给了谁?“三傻笑了:“这跟我有屁相干?”
你苦苦思索了一夜,第二天,你走入林中大叫:“十傻,你在哪?”
一个头上带着10号草帽的人,十傻,应声而出:“老爷,你有什么事?”“
我要你帮把1到10号盘子搬到C柱““好的,老爷。“十傻转身就向林内走。
“慢着,你该不是回去叫你兄弟九傻吧““老爷你怎么知道的?“
“所以你使唤他把头九个盘子搬过来搬过去,你只要搬几次十号盘就好了,
对吗?““对呀!““你知不知道他是怎么干的?““这和我有屁相干?
“你叹了一口气,决定放弃。十傻开始干活。树林里充满了此起彼伏的叫声:
“九傻,来一下!“ “老八,到你了!““五傻!。。。“”三傻!。。。“
”大傻!“你注意到大傻从不叫人,但是大傻的工作也最简单,他只是把一号盘搬来搬去
。若干年后,工作结束了。十傻来到你面前。你问十傻:“是谁教给你们这么干活的?“
十傻说:“我爸爸。他给我留了这张纸条。”他从口袋里掏出一张小纸条,上面写着:
“照你帽子的号码搬盘子到目标柱。如果有盘子压住你,叫你上面一位哥哥把他搬走。
如果有盘子占住你要去的柱子,叫你哥哥把它搬到不碍事的地方。等你的盘子搬到了目标
,叫你哥哥把该压在你上面的盘子搬回到你上头。“你不解地问:“那大傻没有哥哥怎么办
?“十傻笑了:“他只管一号盘,所以永远不会碰到那两个‘如果’,也没有盘子该压在一号上啊。
”但这时他忽然变了颜色,好像泄漏了巨大的机密。他惊慌地看了你一眼,飞快地逃入树林。第二天
,你到树林里去搜寻这十兄弟。他们已经不知去向。你找到了一个小屋,只容一个人居住,但是屋里
有十顶草帽,写着一到十号的号码。

2.青蛙跳台阶问题

问题:一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法?

同样,我们先从简单的开始分析,不难分析出:

台阶数 方法数
1 1
2 2
3 3
4 5
5 8

我们不难发现,从第三个数开始,每个方法数都是前两个方法数的和,这类似于斐波那契数列,所以也可以使用递归来解。

public class TestDemo {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int n = scan.nextInt();

        int x = fac(n);
        System.out.println(x);
    }

    public static int fac(int n) {
        if (n == 1) {
            return 1;
        } else if (n == 2) {
            return 2;
        } else {
            return fac(n - 2) + fac(n - 1);
        }

    }
}

只要我们把前两种这个特殊情况先列出来,其他的就按照n-2和n-1项的和来不断递归就可以了。

猜你喜欢

转载自blog.csdn.net/AIJXB/article/details/104866993