【递归】Hanoi双塔问题,如何去找状态方程

这篇具有很好参考价值的文章主要介绍了【递归】Hanoi双塔问题,如何去找状态方程。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

引言


汉诺塔问题是计算机科学中经典的问题之一,也是计算机科学入门课程中常见的问题。汉诺塔问题的解法可以让我们了解到递归算法的实现方法,也可以帮助我们深入理解递归算法的本质。在本文中,我们将介绍汉诺塔问题的定义和解法,并给出具体的实现过程以及测试案例。

问题描述


【题目】给定A,B,C三根足够长的细柱,在A柱上放有n个中间有空的圆盘,共有n个不同的尺寸。现要将 这些国盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2) A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An。
【示例】
输入:3
输出:7
【递归】Hanoi双塔问题,如何去找状态方程
汉诺塔问题是一个经典的数学问题,它由三根柱子和N个圆盘组成,其中圆盘的尺寸不同,且初始时按从小到大的顺序依次排列在第一根柱子上。现在要求将所有的圆盘都移到第三根柱子上,并且每次只能移动一个圆盘,且在移动过程中必须保证每根柱子上的圆盘仍然保持上小下大的顺序。请问如何移动才能使得所有圆盘都移到第三根柱子上,且符合要求?|

解析

我们先看看当圆盘数由1到3的情况:
【递归】Hanoi双塔问题,如何去找状态方程
我们就可以得到以下数据:

圆盘数 移动次数
1 1
2 3
3 7
  • 具体来说,我们可以将第一个柱子上的n-1个圆盘移动到第二个柱子,再将第一个柱子上的最后一个圆盘移动到第三个柱子,最后再将第二个柱子上的n-1个圆盘移动到第三个柱子上。在移动的过程中,我们需要保证每根柱子上的圆盘仍然按照上小下大的顺序排列。这里很明显可以得到状态方程:
    F ( n ) = 2 F ( n − 1 ) + 1 F(n)=2F(n-1)+1 F(n)=2F(n1)+1
    【递归】Hanoi双塔问题,如何去找状态方程

实现过程

  • 在实现过程中,我们需要定义一个递归函数来实现汉诺塔问题的解法。下面是递归函数的伪代码:
hanoi(n, a, b, c):
    if n == 1:
        move a to c
    else:
        hanoi(n-1, a, c, b)
        move a to c
        hanoi(n-1, b, a, c)

其中,n表示当前要移动的圆盘数量,a、b、c分别表示三根柱子的名称,move a to c表示将柱子a上的一个圆盘移动到柱子c上。在递归的过程中,我们需要将上面的n-1个圆盘从a柱移动到b柱,再将最底下的一个圆盘从a柱移动到c柱,最后将b柱上的n-1个圆盘移动到c柱。

递归题解

int hanoi(int n, char a, char b, char c) {
    if (n == 1) {
        return 1;
    } else {
        int count = hanoi(n-1, a, c, b);
        count++;
        count += hanoi(n-1, b, a, c);
        return count;
    }
}

当然也可以根据状态方程遍历

//计算2*(2^n-1)的值。
 
#include <stdio.h>
 
int main() {
    int n = 0;//圆盘的个数,说到底就是你想算2的多少次幂
    scanf("%d", &n);
    int bigNumber[n];//用于存储超级大数,当然这里的n你可以写成100、1000、10000都行
 
    //先把数组初始化元素全部设为0
    for (int i = 0; i < n; ++i) {
        bigNumber[i] = 0;
    }
 
    //开始计算2^n,注意这里仅仅是计算2^n、2^n、2^n,还没到减1的那一步
    //注意,这里是将数组“颠倒”使用的,bigNumber[0]表示大数的最后一位(个位数字),bigNumber[n]表示大数的最高位,至于原因,看下去就知道了
     
     
    bigNumber[0] = 1;//第一位等于1,以便进行乘积运算,要不然0^n结果全部都是0
    for (int i = 0; i < n; ++i) {//这里的n表示乘积次数,你想求2的多少次幂,这里就写几
        for (int j = 0; j < n; ++j) {
            bigNumber[j] *= 2;//每次遍历,数组中的每一位都要乘2。例如计算123*2时,1、2、3都要乘2,这里原理一样
        }
         
        //乘法做完了,现在开始挨个位检查,看看哪位数值超过了9
        for (int k = 0; k < n; ++k) {
            if (bigNumber[k] > 9) {
                bigNumber[k+1]++;//如果某一位数超过了9,则需要进位
                bigNumber[k] = bigNumber[k]%10;//进位后自身取余,例如13%10=3
            }
        }
    }
 
     
     
    //现在开始执行2^n-1操作
    bigNumber[0]-= 1;//放心减1,因为2^n个位数绝对只能是2、4、8、6...
 
     
     
    //现在开始执行2*(2^n-1),说白了也就是将大数整体再乘一次2,原理同上方的次幂完全相同,只不过部分位置的循环条件发生变化
     
    for (int i = 0; i < 1; ++i) { //这里的i从n变为1,就变了这一个地方,因为只进行一次乘2操作,其余的啥都没变
         
        for (int j = 0; j < n; ++j) {
            bigNumber[j] *= 2;//每次遍历,数组中的每一位都要乘2,例如123*2时1、2、3都要乘2
        }
         
        //乘法做完了,现在开始挨个位检查,看看哪位数值超过了9
        for (int k = 0; k < n; ++k) {
            if (bigNumber[k] > 9) {
                bigNumber[k+1]++;//如果某一位数超过了9,则需要进位
                bigNumber[k] = bigNumber[k]%10;//进位后自身取余, 例如13%10=3
            }
        }
    }
 
 
    //好了,结果已经计算完毕,现在就是输出结果
    for (int i = n-1; i >= 0 ; --i) {
        //数组中可能出现一些位为0,没用上,那就把这些0找出来,例如123450000000000,后面的那一堆0要他何用?不输出它
        if (bigNumber[i] > 0) {
         
            //找到了第一个不为0的位,也就是大数的“最高位”,注意,这里是将数组“颠倒”使用的,bigNumber[0]表示大数的最后一位(个位数字),
            //bigNumber[n]表示大数的最高位,至于原因,看下去就知道了
            for (int j = i; j >= 0; --j) {  //"倒“着输出数组的每一位即可
                printf("%d", bigNumber[j]);
            }
            break;
        }
    }
    return 0;
}

如果你想输出每个步骤,这里由一段简单的示例:

#include <stdio.h>

int hanoi(int n, char a, char b, char c) {
    if (n == 1) {
        printf("将第%d个盘子从%c移动到%c\n", n, a, c);
        return 1;
    } else {
        int count = hanoi(n-1, a, c, b);
        printf("将第%d个盘子从%c移动到%c\n", n, a, c);
        count++;
        count += hanoi(n-1, b, a, c);
        return count;
    }
}

int main() {
    int n;
    printf("请输入盘子的数量:");
    scanf("%d", &n);
    int count = hanoi(n, 'A', 'B', 'C');
    printf("总共需要移动的次数: %d\n", count);
    return 0;
}

请输入盘子的数量:3
将第1个盘子从A移动到C
将第2个盘子从A移动到B
将第1个盘子从C移动到B
将第3个盘子从A移动到C
将第1个盘子从B移动到A
将第2个盘子从B移动到C
将第1个盘子从A移动到C
总共需要移动的次数: 7文章来源地址https://www.toymoban.com/news/detail-413801.html

到了这里,关于【递归】Hanoi双塔问题,如何去找状态方程的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数学建模-python递归、lingo解多元一次方程

    在了解如何用python、lingo解多元一次方程问题之前我们先了解什么是递归,因为python解多元一次方程问题是递归算法的一个经典算法习题,也是python解多元一次方程问题用到的主要算法。 简单说程序调用自身的编程技巧叫递归。递归的思想是把一个大型复杂问题层层转化为一

    2024年01月25日
    浏览(38)
  • 动态规划——状态转移方程

    DP问题的核心即确定动态转移方程。 (1)寻找变量,确定子问题。DP表一般为二维,故需要两个变量。 (2)寻找总问题与子问题迭代关系,确定中间值、迭代值 例1: 有5个物品,其重量分别是{2, 2, 6, 5, 4},价值分别为{6, 3, 5, 4, 6},背包的容量为10,计算背包所能装入物品的

    2023年04月08日
    浏览(29)
  • 动态系统建模-状态空间方程

    状态空间方程是现代控制理论的基础, 它以矩阵的形式表达系统状态变量、 输入及输出之间的关系。 它可以描述和处理多输入多输出(MultipleInput Multiple Output, MIMO) 的系统。 拉普拉斯变换后 状态空间方程是一个集合, 它包含了系统的输入、 输出及状态变量, 并把它们用一系列的

    2024年02月12日
    浏览(29)
  • 卡尔曼滤波 - 状态空间模型中的状态方程

    卡尔曼滤波 - 状态空间模型中的状态方程 flyfish 状态方程和观测方程统称为状态空间模型  位移 = Δ x = x f − x 0 text { 位移}=Delta x=x_f-x_0   位移 = Δ x = x f ​ − x 0 ​ x 0 x_0 x 0 ​ 是起始位置 x f x_f x f ​ 是终止位置 在坐标轴里,右边是正,左边是负 绿色矩形的高度为 v 0 v

    2024年02月02日
    浏览(29)
  • 【Algorithm】动态规划和递归问题:动态规划和递归有什么区别?如何比较递归解决方案和它的迭代版本?

    动态规划(Dynamic Programming,DP)和递归(Recursion)是解决复杂问题的两种不同方法,它们在计算机科学中常用于解决具有重叠子问题和最优子结构特性的问题。 1.1 递归 (Recursion)定义及优缺点 递归是一种通过将问题分解为更小的子问题来解决问题的方法。在递归中,一个函数

    2024年03月17日
    浏览(35)
  • 级联、串联、并联求传递函数的方框图和状态方程

    目录 一、基础知识 1.传递函数 2.状态方程 二、方法论 1.级联法 2.串联法 3.并联法 三、画系统框图,求状态方程 1.传递函数 2.级联法画系统框图,求状态方程 3.串联法画系统框图,求状态方程 4.并联法画系统框图,求状态方程 传递函数是指零初始条件下线性系统响应(即输出

    2024年02月07日
    浏览(49)
  • NLP文本匹配任务Text Matching [有监督训练]:PointWise(单塔)、DSSM(双塔)、Sentence BERT(双塔)项目实践

    本项目对3种常用的文本匹配的方法进行实现:PointWise(单塔)、DSSM(双塔)、Sentence BERT(双塔)。 文本匹配(Text Matching)是 NLP 下的一个分支,通常用于计算两个句子之间的相似程度,在推荐、推理等场景下都有着重要的作用。 举例来讲,今天我们有一堆评论数据,我们

    2024年02月12日
    浏览(26)
  • 如何解决Pod一直处于Pending状态的问题

    在Kubernetes集群中,当我们创建一个新的Pod或更新一个Pod时,可能会遇到Pod一直处于Pending状态的问题。本文将介绍解决这个问题的几种方法。 检查Node节点的状态 Pod在Kubernetes中必须运行在Node节点上。因此,如果没有可用的Node节点或者Node节点不可用,Pod就会被挂起。可以使用

    2024年02月06日
    浏览(39)
  • Android问题笔记 -如何实现代码控制自动旋转开关的变更以及当前状态

    专栏分享 点击跳转=Unity3D特效百例 点击跳转=案例项目实战源码 点击跳转=游戏脚本-辅助自动化 点击跳转=Android控件全解手册 点击跳转=Scratch编程案例 点击跳转=软考全系列 众所周知,人生是一个漫长的流程,不断 克服困难 ,不断反思前进的过程。在这个过程中会产生很多对

    2024年02月08日
    浏览(36)
  • 【状态估计】变分贝叶斯近似的递归噪声自适应卡尔曼滤波(Matlab代码实现)

    💥💥💞💞 欢迎来到本博客 ❤️❤️💥💥 🏆博主优势: 🌞🌞🌞 博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️ 座右铭: 行百里者,半于九十。 📋📋📋 本文目录如下: 🎁🎁🎁 目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码及文献 文献来

    2024年02月09日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包