首页 > 其他分享 >汉诺塔问题及其变种问题解法(cpp版本)

汉诺塔问题及其变种问题解法(cpp版本)

时间:2022-11-11 19:23:48浏览次数:50  
标签:柱子 圆盘 问题 次数 汉诺塔 cpp 移动 解法

普通汉诺塔问题

1. 问题描述

有三个柱子A、B、C,A柱子上有n个圆盘,圆盘的大小不等,大圆盘的在下,小圆盘的在上。
将A柱子上的圆盘全部移动到C柱子上。每次只能移动一个圆盘,而且在移动的过程中,三个柱子上的圆盘始终保持大圆盘在下,小圆盘在上。

2. 问题输入

A柱子上的圆盘数量,当输入为0时,程序结束。

3. 程序输出

圆盘移动的过程和圆盘移动的总次数。

4. 递推公式

由于圆盘需要通过B柱,从A柱转移到C柱,因此可以设H(n)表示n个圆盘从A柱到C的移动次数。
则首先领前n-1个圆盘由A柱移动到B柱,有移动次数H(n-1),然后将最大的圆盘从A柱移动到C柱需要移动1次,
然后问题就转化为了将 n-1 个圆盘从B柱通过A柱移动到C柱,有移动次数H(n-1)

因此我们可以得到递推公式:

  • H(1) = 1;
  • H(n) = H(n - 1) + 1 + H(n - 1) = 2 * H(n - 1) + 1;

5. 问题代码(cpp版本)

/***
 * Author : DL1024
 * Date   : 2022-11-11
 * ***/

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

inline void move(int number, char x, char y){
    cout << number << " 号圆盘从 " << x << " 移动到 " << y << endl;
}

int Hanio(int n, char A, char B, char C){
    ll cnt1 = 0, cnt2 = 0;
    if (n == 1){
        move(1, A, C);
        return 1;
    } else{
        cnt1 = Hanio(n - 1, A, C, B);   // n-1个从A移动到B柱
        move(n, A, C);                  // 把n号盘从A移动到C
        cnt2 = Hanio(n - 1, B, A, C);   // n-1个从B移动到C
        return cnt1 + 1 + cnt2;
    }
}

int main( ){
    cout << "汉诺塔问题解决方案:\n";
    ll cnt = 0;
    int n = 0;
    do{
        cout << "请输入A柱子上面的圆盘数量n:";
        if (cin >> n){
            if (n == 0) break;
            cnt = Hanio(n, 'A', 'B', 'C');
            cout << n << "个圆盘从A移动到C的总次数为" << cnt << endl;
        } else break;
    } while (1);

    return 0;
}

汉诺塔问题变形

1. 问题描述

有三个柱子A、B、C,A柱子上有n个圆盘,圆盘的大小不等,大圆盘的在下,小圆盘的在上。
将A柱子上的圆盘全部移动到C柱子上。每次只能移动一个圆盘,而且在移动的过程中,三个柱子上的圆盘始终保持大圆盘在下,小圆盘在上。

另外,不允许直接从A柱子移动到C柱子或直接从C柱子移动到A柱子,即每次移动一定是移动到中间柱子B或者从中间柱子B移走。

例如,当A柱子上只有一个圆盘时,首先将这个圆盘从A柱子移动到中间柱子B,再从中间柱子B移动到C柱子,总共移动次数是2。

2. 问题输入

A柱子上的圆盘数量,当输入为0时,程序结束。

3. 程序输出

圆盘移动的过程和圆盘移动的总次数。

4. 递推公式

由于圆盘必须需要通过B柱,从A柱转移到C柱或者从C柱转移到A柱,因此可以设H(n)表示n个圆盘从A柱到C的移动次数。
则首先领前n-1个圆盘由A柱移动到C柱,有移动次数H(n-1),然后将最大的圆盘从A柱移动到B柱需要移动1次,接下来将n-1个圆盘由C柱通过B柱再移动到A柱,有移动次数H(n-1),然后再将最大的圆盘从B柱移动到C柱需要1次,然后问题就转化为了将 n-1 个圆盘从A柱通过B柱移动到C柱,即有移动次数H(n-1)

因此我们可以得到递推公式:

  • H(1) = 1;
  • H(n) = H(n - 1) + 1 + H(n - 1) + 1 + H(n - 1)= 3 * H(n - 1) + 2;

5. 问题代码(cpp版本)

/***
 * Author : DL1024
 * Date   : 2022-11-11
 * ***/

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

void move(int number, char x, char y){
    if (x == 'B' || y == 'B'){
        cout << number << " 号圆盘从 " << x << " 移动到 " << y << endl;
    } else{
        // x经过B到y
        cout << number << " 号圆盘从 " << x << " 移动到 " << "B" << endl;
        cout << number << " 号圆盘从 " << "B" << " 移动到 " << y << endl;
    }
}

int Hanio(int n, char A, char B, char C){
    ll cnt1 = 0, cnt2 = 0, cnt3 = 0;
    if (n == 1){
        move(1, A, C);  // 只有一个圆盘的时候,先移动到B盘,再移动到C盘,2次
        return 2;
    } else{
        cnt1 = Hanio(n - 1, A, B, C);   // n-1个从A移动经过B到C
        move(n, A, B);                  // n号盘从A移动到B
        cnt2 = Hanio(n - 1, C, B, A);   // n-1个从C移动经过B到A
        move(n, B, C);                  // n号盘从B移动到C
        cnt3 = Hanio(n - 1, A, B, C);   // n-1个盘从A移动经过B到C
        return cnt1 + 1 + cnt2 + 1 + cnt3;
    }
}

int main( ){
    cout << "汉诺塔问题解决方案:\n";
    ll cnt = 0;
    int n = 0;

    do{
        cout << "请输入A柱子上面的圆盘数量n:";
        if (cin >> n){
            if (n == 0) break;
            cnt = Hanio(n, 'A', 'B', 'C');
            cout << n << "个圆盘从A移动到C的总次数为" << cnt << endl;
        } else break;
    } while (1);

    return 0;
}

标签:柱子,圆盘,问题,次数,汉诺塔,cpp,移动,解法
From: https://www.cnblogs.com/DL1024/p/16881500.html

相关文章

  • Linux 终端编译后运行.c/.cpp文件中文乱码问题
    目录​​一、异常错误​​​​二、原因​​​​三、解决方法​​​​1.首先确保源代码编码格式是UTF-8​​​​2.确保Linux运行语言支持中文​​一、异常错误发现通过VS2019......
  • 数值分析实验4:线性方程组的迭代法解法
    线性方程组的迭代法解法(一)实验目的与要求1.通过编程计算实践,理解体会古典迭代法的思想。2.通过编程计算实践,熟练各种算法的计算流程。3.通过各种方法对同一题目的求解,......
  • 拓端tecdat|R语言代写用Rcpp加速Metropolis-Hastings抽样估计贝叶斯逻辑回归模型的参
    在最近的一篇文章中,我描述了一个Metropolis-in-Gibbs采样器,用于估计贝叶斯逻辑回归模型的参数。 这篇文章就此问题进行了研究,以展示Rcpp如何帮助克服这一瓶颈。 TLDR:只需......
  • cpp-inheritance
    如何在OI中优雅地使用继承?postedon2022-08-1220:02:40|under学术|sourcetemplate<intN>structdsu{intfa[N+10],siz[N+10],cnt;dsu(intn=N):cnt......
  • 字符串逆序(多种解法)
    1:>#define_CRT_SECURE_NO_WARNINGS1#include<stdio.h>#include<string.h>voidreverse_string(chararr[]){intl=0;intr=strlen(arr)-1;while(l<r){......
  • 最大子段和の解法
    前缀和皆用此题首先打出一份\(O(n^3)\)的暴力代码for(intl=1;l<=n;l++) for(intr=l;r<=n;r++){ sum=0; for(intk=l;k<=r;k++) sum+=a[k]......
  • cpp 并行编程 pthread 框架 绑定核心运行
    1#include<stdio.h>2#include<math.h>3#include<pthread.h>4#include<stdio.h>5#include<iostream>6#include<stdlib.h>7#include<time.h>......
  • activemq-cpp getCMSType类型判断是否有效
    场景   CMS消息类型有BytesMessage,TextMessage,MapMessage,StreamMessage,是否可以通过getCMSType知道是哪一个类型的消息?答案    不行,依然需要通过constcms::By......
  • cpp基础之二-结构体structure
    数组必须是同一类型type的集合,而结构体则是不同类型type的集合,类似python中的数组结构体的定义//长方形结构体structRectangle{intlength;intwi......
  • c/cpp基础之一:数组array
    在熟悉数组之前,我们先来认识一下在c/cpp中的mainmemory结构是什么样子的(简化版):heap堆stack栈codesection数组的声明与初始化intA[5];//声明int......