C语言解决汉诺塔问题

目录

题目

对小数值m的简单剖析

当 m=1 时

当 m=2 时

函数move的解析

当 m=3 时

分析步骤(1)(3)递归

   步骤(1)的递归分解

步骤(2) 

步骤(3)的递归分解

大数值m=64 

 完整代码


题目

Hanoi(汉诺)塔问题。这是一个古典的数学问题,是一个用递归方法解题的典型例子。问题是这样的:古代有一个梵塔,塔内有3座A,B,C。开始时A座上有64个盘子,盘子大小不等,大的在下,小的在上(如图)。有一个老和尚想把这64个盘子从A座移到C座,但规定每次只允许移动一个盘,且在移动过程中在3个座上都始终保持大盘在下,小盘在上。在移动过程中可以利用B座。要求输出移动盘子的步骤。

对小数值m的简单剖析

当一个题目难以解决的时候,我们就要学会将这个难题进行简化。

我们会创建一个函数hanoi,函数的功能就是将m个盘子从a转移到c

当 m=1 时

我们只需要A -> C 就可以了。 

int main()
{
    hanoi(m,'A','B','C');//这里简洁写,是为了方便理解。
}
void move(char x,char y)//move函数功能只是将结果打印出来
{
    printf("%c->%c\n");
}

void haoni(int m,char a,char b,char c)//m=1进入函数,将1个盘子从a转移到c.
{
    if(m==1)
        move(a,c);
}

当 m=2 时

当m=2时,操作又会有些不同,往后的(1)(3)盘数会发生改变,所以这里的(1)(3)就提前用递归的方式解决

(1)先将1个盘从A放到B

// m=2,将m-1个盘子从A移到B 

(2)再把A的1个盘放到C

(3)最后把B的1个盘放到C

// m=2,将m-1个盘子从B移到C

A->B A->C B->C 

因为hanoi的功能就是把m个盘子从a移到c

所以我们想要从A移到B时,我们只需要,传参的时候将A照常赋给a将B赋给c就可以了。

int main()
{
    hanoi(m,'A','B','C');//这里简洁写,是为了方便理解。m=2
}
void haoni(int m,char a,char b,char c)//m=2从这里进来,haoni的功能就是把m个盘子从A移动到C
{
    if(m==1)
        move(a,c);//跳过
    else
    {
        hanoi(m-1,a,c,b);//步骤(1)先将1个盘从A放到B,实参为a,c,b,传过去的数据顺序实际为A,C,B
        move(a,c);       // 步骤(2)再把A的一个盘放到C 
        haoni(m-1,b,a,c);// 步骤(3)最后把B的盘放到C,实参为b,a,c,传过去的数据顺序实际为B,A,C
    }
}
//进一步分析
//步骤(1)
hanoi(int m,char a,char b,char c)//m=1,由于传来的数据顺序为,A,C,B,因此这里的a=A,b=C,c=B
{
    if(m=1)
        move(a,c);//打印的结果为 A->B

//后面的函数没有用到就不多余写了
}
//步骤(2)
void move(char x,char y)//move的参数是(a,c),a='A',b='B',c='C',
{
    printf("%c->%c\n");//结果:A->C
}
//步骤(3)
hanoi(int m,char a,char b,char c)//m=1,由于传来的数据顺序为,A,C,B,因此这里的a=B,b=A,c=C
{
    if(m=1)
        move(a,c);//打印的结果为 B->C

//后面的函数没有用到就不多余写了
}

函数move的解析

void move(char x,char y)
{
    printf("%c->%c\n");
}

void haoni(int m,char a,char b,char c)
{
    if(m==1)
        move(a,c);
}
//因为函数move的实参是a,c,其实move打印的都是传过来的形参顺序的第一个和第三个
//void haoni(int m,char a,char b,char c),
1.如果传给函数haoni的参数是,'A','B','C'
move打印的就是A->C
2.如果传给函数haoni的参数是,'A','C','B'
move打印的就是A->B
3.如果传给函数haoni的参数是,'B','A','C'
move打印的就是B->C

当 m=3 时

递归就是从结果递推回去,将步骤简化,难的步骤就用递归分解

我们建立函数hanoi( m,'A','B','C'),函数的作用就是把a座上的m个盘子移到c座上

(1)将A座上2个盘子一道B座上(借助C座)//需要用到递归分解

(2)将A座上1个盘子一道C座上,

(3)将B座上2个盘子一道C座上(借助A座)//需要用到递归分解

分析步骤(1)(3)递归

分解(1)(3)步骤中将2个盘子从一个柱子移到另一个柱子。

(1)将两个盘子从A移到B,是不是和m=2时(将2个盘子从A移到C的原理是一样的),只不过这里是从A移动到B,通过改变'A','B','C'传过去的顺序,我们就可以实现从A移动到B。

(3)(c)->(d)我们要解决的是如何将两个盘子从B移到C,其实和(1)本质上是一样的,都是将m-1个盘子从一个柱子转移到另一个柱子上,我们都可以通过hanoi函数完成。

int main()
{
    hanoi(m,'A','B','C');//这里简洁写,是为了方便理解。m=3
}
void haoni(int m,char a,char b,char c)//m=3进入函数
{
    if(m==1)
        move(a,c);//跳过
    else
    {
        hanoi(m-1,a,c,b);//步骤(1)m-1=2,这里的a='A',b='B',c='C',所以传过去的是'A','C','B'
        move(a,c);
        haoni(m-1,b,a,c);//步骤(3)m-1=2,这里的a='A',b='B',c='C',所以传过去的是'B','A','C'
    }
}

   步骤(1)的递归分解

//步骤(1)
hanoi(int m,char a,char b,char c)//由于传来的数据顺序为,A,C,B,因此这里的a=A,b=C,c=B
                                 //这里的m=2
{
    if(m=1)
        move(a,c);//跳过
     else
    {
        hanoi(m-1,a,c,b);//步骤(1.1)m-1=1,a=A,b=C,c=B,那么我们传过去的是'A','B','C'
        move(a,c);
        haoni(m-1,b,a,c);//步骤(1.3)m-1=1,a=A,b=C,c=B,那么我们传过去的是'C','A','B'
    }
}
//步骤(1.1)
hanoi(int m,char a,char b,char c)//m=1,由于传来的数据顺序为,A,B,C,因此这里的a=A,b=B,c=C
{
    if(m=1)
        move(a,c);//打印的结果为 A->C

//后面的函数没有用到就不多余写了
}
//步骤(1.2)
void move(char x,char y)//move的参数是(a,c),a='A',b='C',c='B',
{
    printf("%c->%c\n");//结果:A->B
}
//步骤(1.3)
hanoi(int m,char a,char b,char c)//m=1,由于传来的数据顺序为,C,A,B,因此这里的a=C,b=A,c=B
{
    if(m=1)
        move(a,c);//打印的结果为 C->B

//后面的函数没有用到就不多余写了
}

步骤(2) 

//步骤(2)
void move(char x,char y)//move的参数是(a,c),a='A',b='B',c='C',
{
    printf("%c->%c\n");//结果:A->C
}

步骤(3)的递归分解

//步骤(3)
hanoi(int m,char a,char b,char c)//由于传来的数据顺序为,B,A,C,因此这里的a=B,b=A,c=C
                                 //这里的m=2
{
    if(m=1)
        move(a,c);//跳过
     else
    {
        hanoi(m-1,a,c,b);//步骤(3.1)m-1=1,a=B,b=A,c=C,那么我们传过去的是'B','C','A'
        move(a,c);
        haoni(m-1,b,a,c);//步骤(3.3)m-1=1,a=B,b=A,c=C,那么我们传过去的是'A','B','C'
    }
}
//步骤(3.1)
hanoi(int m,char a,char b,char c)//m=1由于传来的数据顺序为,B,C,A,因此这里的a=B,b=C,c=A
{
    if(m=1)
        move(a,c);//打印的结果为 B->A

//后面的函数没有用到就不多余写了
}
//步骤(3.2)
void move(char x,char y)//move的参数是(a,c),a='B',b='A',c='C',
{
    printf("%c->%c\n");//结果:B->C
}
//步骤(3.3)
hanoi(1,char a,char b,char c)//m=1,由于传来的数据顺序为,A,B,C,因此这里的a=A,b=B,c=C
{
    if(m=1)
        move(a,c);//打印的结果为 A->C

//后面的函数没有用到就不多余写了
}

大数值m=64 

大数值的代码,也只是m的数值发生改变,通过下面的代码依旧可以运行。 

 完整代码

#include<stdio.h>

void move(char x,char y)
{
    printf("%c->%c\n");
}

void haoni(int m,char a,char b,char c)
{
    if(m==1)
        move(a,c);
    else
    {
        hanoi(m-1,a,c,b);
        move(a,c);
        haoni(m-1,b,a,c);
    }
}

int main()
{
    int m=0;
    printf("请输入盘子的数量:")'
    scanf("%d",&m)
    printf("移动 %d 盘子的步骤:\n",m);
    haoni(m,'A','B','C');
    return 0;
}

  • 27
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪巴戒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值