汉诺塔问题

1 问题描述

有A,B,C三个柱子,A柱子上从上到下,从小到大排列着n个圆盘。现要求将A柱子上的n个圆盘全部移动到C柱子上,依然按照从上到下,从小到大的顺序排列。且对移动过程要求如下:

a)一次只能移动一个盘子。

b)移动过程中大盘子不允许出现在小盘子上方。

问:总共需要移动的步数是多少?

2 化繁为简,分析题目

从宏观角度来分析,将移动步骤分为三步:

a)将最上面的n-1个盘子移动到B柱子上

b)将最大的盘子移动到C柱子上

c)再将B柱子上的n-1个盘子移动到C柱子上

完成以上三步,即可达到目标。因此,问题转化为如何移动n-1个盘子?同样的思路解决n-1个盘子移动的问题,可以发现其中规律。假设移动n个盘子需要的步数为f(n),则移动n-1个判断需要f(n-1)步。

因此,得到递推公式:f(n) = 2 * f(n - 1) + 1

3 求解递推公式

将上一步的递推式进行变形:f(n) + 1 = 2(f(n - 1) + 1),设q(n) = f(n) + 1, 则q(n) = 2q(n-1), q(n) / q(n-1) = 2,可见q(n) 是一个等比序列,q(1) = 2,因此q(n) = 2^n(n >= 1), f(n) = 2^n - 1。

4 java编程实现递归算法

public class TowerOfHanoi {

    // 统计移动次数
    static int count = 0;

    public static void main(String[] args) {
        char a = 'A';
        char b = 'B';
        char c = 'C';
        int n = 3;
        TowerOfHanoi test = new TowerOfHanoi();
        test.recurse(n, a, b, c);
        System.out.println(count);
    }

    // 移动一次
    private void move(int n, char from, char to){
        count = count + 1;
        System.out.println("将圆盘" + n + "号, 从" + from + "移动到" + to);
    }

    // 递归
    private void recurse(int n, char a, char b, char c){
        // 递归结束条件:n == 1,只一个盘子时
        if (n == 1){
            move(1, a, c);
        } else {
            recurse(n - 1, a, c, b);
            move(n, a, c);
            recurse(n - 1, b, a, c);
        }
    }
}

 

转载于:https://www.cnblogs.com/mydesky2012/p/11514302.html

// helloworld.cpp : Defines the entry point for the console application. // //by 陈墨仙 2019-07-18 //完全不用递归解汉诺塔 #include "stdafx.h" #include <windows.h> int h[34];//为了便于理解,0号元素不用,33个盘子 int a[4][34]; int b[4]; int jihao; int dijici; void printH() { //system("cls"); for(int i = 1;i<=34;i++) { printf("%d:%d\t",i,a[3][i]); } } bool jiancha(int * h)//检测是否在下面的都是编号小的 { int d[4]; d[1]=0; d[2]=0; d[3]=0; for(int j = 1;j<4;j++) { for(int i = 1;i<34;i++) { if(a[j][i]==0 || a[j][i]>a[j][i-1]) { } else { printf("error a[%d][%d] = %d a[%d][%d]=%d",j,i-1,a[j][i-1],j,i,a[j][i]); scanf("%d"); return false; } } } return true; } bool shunxu(int zhuzi) { for(int i = 1; i< b[zhuzi];i++) { if(a[zhuzi][i]==34-i) { } else { return false; } } return true; } bool chenggong(int n,int zhuzi)//n号盘是否都移到3 { int d = 0; int t = 34; for(int i = 33;i>33-n;i--) { if(a[zhuzi][34-i]!=i-n+1) { return false; } } return true; } int jc3()//检测3号柱的盘子有几个 { int d = 0; int t = 34; for(int i = 33;i>0;i--) { if(h[i]==3) { d=d+1; t = i; } } return d; } int jc1()//检测1号柱的盘子有几个 { int d = 0; int t = 34; for(int i = 33;i>0;i--) { if(h[i]==1) { d=d+1; t = i; } } return d; } void initH() { for(int i = 0;i<34;i++) { h[i]=1; a[1][i]=i; a[2][i]=0; a[3][i]=0; } b[1]=34; b[2]=1; b[3]=1; } int jc2()//检测2号柱从33往下盘子有几个 { int d = 0; int t = 34; for(int i = 33;i>0;i--) { if(h[i]==2) { d=d+1; t = i; } } return d; } int getTop(int zhuzi) { int d = 0; int t = 0; for(int i = 1;i<34;i++) { if(h[i]==zhuzi && i>t) { t = i; } } return t; } bool jiou(int s) { if(s % 2 == 0) { return true; } else { return false; } } void change(int i,int yuan,int mubiao) { if(h[i] == yuan) { h[i] = mubiao; a[mubiao][b[mubiao]]=i; b[mubiao]=b[mubiao]+1; a[yuan][b[yuan]]=0; b[yuan]=b[yuan]-1; printf("h[%d]:%d->%d",i,yuan,mubiao); } else { printf("Error h[%d] = %d",i,h[i]); scanf("%d"); } jiancha(h); } int FastLog2(int x) { float fx; unsigned long ix, exp; fx = (float)x; ix = *(unsigned long*)&fx; exp = (ix >> 23) & 0xFF; return exp - 127; } int chu2(int n ,int cishu) { for(int j = 1; j<= cishu;j++) { n=n/2; } return n; } void jihaopan(int n) { int i = 1; int yuan = n; while(1) { if(n%2==1) { jihao = i; dijici = chu2(yuan,i)+1; break; } n=n/2; i=i+1; } //printf("几号盘%d,第几次%d",jihao,dijici); } int main(int argc, char* argv[]) { printf("汉诺塔!\n"); int times = 0; initH(); int ji = 1; for(int i = 1;i<5559060534555523;i++) { jihaopan(i); if(jiou(jihao)==false) { int tmp; tmp = dijici%3; if(tmp==1) { change(getTop(1),1,3); } else if(tmp==2) { change(getTop(3),3,2); } else { change(getTop(2),2,1); } } else { int tmp; tmp = dijici%3; if(tmp==1) { change(getTop(1),1,2); } else if(tmp==2) { change(getTop(2),2,3); } else { change(getTop(3),3,1); } } if(chenggong(33,3)) { printf("sssss"); break; } } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值