河内塔 - 如何在每次递归时不跳过钉子

2024-01-18

我的任务是使用递归求解任意数字的河内塔。我用 C++ 编写了代码。

Rules:

  1. 无法将较大的磁盘堆叠在较小的磁盘之上。
  2. 一次无法移动多个磁盘。

** 3. 一次只移动一个圆盘,不要回到起点或离开终点。

如下: 开始 --> peg1 peg2 peg3 --> END

#include <iostream>
#include <time.h>
using namespace std;
void move(int, int, int, int, int, int);
int i, j, l, n;
const int start = 1, end = 5, aux1 = 2, aux2 = 3, aux3 = 4;
int main(){
    double time = 0;
    clock_t begin, stop;
    begin = clock();
    for(n = 10; n>=1; n--){
        l = 0, i = 0, j = 0;
        move(n, start, end, aux1, aux2, aux3);
        cout << "Number of disks moved: " << n << endl;
        cout << "Number of moves made: " << l << endl;
    }
    stop = clock();
    time = (stop - begin)/1000.00;  
    cout << "Game solved in: " << time << " miliseconds";
    return 0;
}
void move(int n, int start, int end, int aux1, int aux2, int aux3){
    if(n>0){
        l++;
        if(i>=100){
            j++;
            if(l - j == i){
                move(n-1, start, aux1, aux2, aux3, end);
                cout << "Move disc " << n << " from peg " << start << " to peg " << end << endl;
                move(n-1, aux1, aux2, aux3, end, start);
            }
        }
        if(i<=100){
                i++;
                move(n-1, start, aux1, aux2, aux3, end);
                cout << "Move disc " << n << " from peg " << start << " to peg " << end << endl;
                move(n-1, aux1, end, aux3, aux2, start);
        }
    }
}

以 3 个磁盘为例,代码如下

Move disc 1 from peg 1 to peg 3
Move disc 2 from peg 1 to peg 2
Move disc 1 from peg 3 to peg 2
Move disc 3 from peg 1 to peg 5
Move disc 1 from peg 2 to peg 4
Move disc 2 from peg 2 to peg 5
Move disc 1 from peg 4 to peg 5
Number of disks moved: 3
Number of moves made: 7

我需要为 3 个磁盘放置算法的示例:

Move disc 1 from peg 1 to peg 2 
Move disc 1 from peg 2 to peg 3
Move disc 1 from peg 3 to peg 4
Move disc 2 from peg 1 to peg 2
Move disc 2 from peg 2 to peg 3
Move disc 1 from peg 4 to peg 3
Move disc 1 from peg 3 to peg 2
Move disc 2 from peg 3 to peg 4
Move disc 1 from peg 2 to peg 3
Move disc 1 from peg 3 to peg 4
Move disc 3 from peg 1 to peg 2
Move disc 3 from peg 2 to peg 3
Move disc 1 from peg 4 to peg 3
Move disc 1 from peg 3 to peg 2
Move disc 2 from peg 4 to peg 3
Move disc 1 from peg 2 to peg 3
Move disc 1 from peg 3 to peg 4
Move disc 2 from peg 3 to peg 2
Move disc 1 from peg 4 to peg 3
Move disc 1 from peg 3 to peg 2
Move disc 3 from peg 3 to peg 4
Move disc 3 from peg 4 to peg 5
Move disc 1 from peg 2 to peg 3
Move disc 1 from peg 3 to peg 4
Move disc 2 from peg 2 to peg 3
Move disc 1 from peg 4 to peg 3
Move disc 1 from peg 3 to peg 2
Move disc 2 from peg 3 to peg 4
Move disc 2 from peg 4 to peg 5
Move disc 1 from peg 2 to peg 3
Move disc 1 from peg 3 to peg 4
Move disc 1 from peg 4 to peg 5
Number of disks moved: 3
Number of moves made: 32

我很迷茫,我不知道如何使代码不让磁盘跳过一个钉子。它可能就在我面前,但我一辈子都无法弄清楚。

请忽略 for 循环“i”和“j”,这些循环的目的是如果结果太大,它将打印前 100 步和最后 100 步。

谢谢你!


基本上每次通话时您都需要执行以下步骤:

  1. 将 n-1 堆圆盘移至第 4 个钉子(向后移动时则移至第 2 个)

  2. 将第 n 个圆盘移至中间(第 3 个钉子)

  3. 将 n-1 堆栈移回第 2 个钉子(即向后移动时的第 4 个钉子)

  4. 将第 n 个光盘移动到目的地

  5. 将 n-1 堆栈移动到目的地

所以你需要 3 次递归调用而不需要记忆。

function hanoi5(n) {
  let out = []
  move(n, 0, 4)
  console.log(out.length + " steps")
  console.log(out.join("\n"))
  function move(n, from, to) {
    if (n == 1) {
      let dir = from < to ? 1 : -1
      for (let i = from; i != to; i += dir)
        out.push("move disc 1 from peg " + (i+1) + " to peg " + (i+1+dir))
    } else if (from < to) {
      move(n - 1, from, 3)
      for (let i = from; i < 2; i++)
        out.push("move disc " + n + " from peg " + (i+1) + " to peg " + (i+2))
      move(n - 1, 3, 1)
      for (let i = 2; i < to; i++)
        out.push("move disc " + n + " from peg " + (i+1) + " to peg " + (i+2))
      move(n - 1, 1, to)
    } else {
      move(n - 1, 3, 1)
      out.push("move disc " + n + " from peg 3 to peg 2")
      move(n - 1, 1, 3)
      out.push("move disc " + n + " from peg 2 to peg 1")
      move(n - 1, 3, 1)
    }
  }
}

hanoi5(3)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

河内塔 - 如何在每次递归时不跳过钉子 的相关文章

  • 二叉树和快速排序?

    我有一个家庭作业 内容如下 别生气 担心 我是not请你帮我做作业 编写一个程序 通过使用二分查找的快速排序方法对一组数字进行排序 树 推荐的实现是使用递归算法 这是什么意思 到目前为止 这是我的解释 正如我在下面解释的那样 我认为两者都有
  • 如何在建立上下文时设置连接超时-PrincipalContext

    using PrincipalContext ctx new PrincipalContext ContextType Domain Domain UserName Password UserPrincipal U new UserPrin
  • 以编程方式更新 Wifi 网络

    我正在尝试创建一个程序 当某个 wifi 网络在范围内时 该程序会连接到该网络 即使已经连接到另一个 wifi 也是如此 我在用着简单Wifi https github com DigiExam simplewifi 基本上效果很好 除了在
  • 图片框、双击和单击事件

    我有一个奇怪的问题 我有一个图片框双击事件以及单击事件 问题是即使我双击该控件 也会引发单击事件 如果我禁用单击事件 则双击事件正在工作 这个问题已经在这里讨论过 https stackoverflow com questions 1830
  • 使用c#在mac上启动外部进程

    我成功地使用 System Diagnostics Process Start 在 Windows 上启动我的外部单声道可执行文件 然而在mac上却失败了 我没有收到任何错误 只是什么也没发生 我尝试按以下方式进行操作 System Dia
  • 在编译输出中添加程序集绑定 (app.config)

    如果我编译应用程序 则会在输出中自动添加程序集绑定 具体的程序集绑定不在app config在 Visual Studio 中但在创建的应用程序配置中 有什么办法可以检查为什么会自动添加程序集绑定吗 选项AutoGenerateBindin
  • 如何在 Windows 上的 GCC 中链接 CS50 C 库

    我是 编程新手 一直在尝试使用以下命令编译我的代码MinGW https en wikipedia org wiki MinGW GCC 但我尝试包括CS50 https en wikipedia org wiki CS50 cs50 c
  • 如何为二进制格式化程序创建 SerializationBinder,以处理类型从一个程序集和命名空间到另一个程序集和命名空间的移动

    上下文如下 我想通过将代码移动到不同的项目来重构代码 其中一些代码包含可序列化的 DTO 用于 跨多个端点发送和接收数据 如果我移动代码 序列化就会中断 因此它不是 向后兼容我的应用程序的旧版本 这个问题的一个解决方案是 Serializa
  • 将两个垂直滚动条相互绑定

    我在控件中有两个 TextBox 并且它们都有两个 VerticalScrollBar 我想在它们之间绑定 VerticalScrollBars 如果一个向上 第二个也会向上等等 如果可以的话我该怎么做 Thanks 不是真正的绑定 但它有
  • 绑定集合的子集

    我有一个ObservableCollection
  • Qt 多重继承和信号

    由于 QObject 我在 QT 中遇到了有关多重继承的问题 我知道很多人也有同样的问题 但我不知道该如何解决 class NavigatableItem public QObject Q OBJECT signals void desel
  • 现代编译器的 C++ 中“memset”功能的状态

    Context 不久前 我偶然发现了 Alexandrescu 在 2001 年发表的 DDJ 文章 http www ddj com cpp 184403799 http www ddj com cpp 184403799 它是关于比较将
  • 如何在C++中列出Python模块的所有函数名称?

    我有一个 C 程序 我想导入一个 Python 模块并列出该模块中的所有函数名称 我该怎么做 我使用以下代码从模块中获取字典 PyDictObject pDict PyDictObject PyModule GetDict pModule
  • Qt - 添加超链接到对话框

    有没有办法在 Qt 对话框中添加可点击的超链接 IE 它应该看起来像一个超链接 蓝色文本 当您单击它时 它应该在浏览器中打开该超链接 像这样的东西 Use QLabel setOpenExternalLinks bool 并在标签上设置文本
  • 从 SQL 语句中检索元数据(表名)

    我使用的是 Visual Studio 2008 我创建了一个 Winforms 应用程序 并且尝试从 SQL 语句中提取表名 con new SqlConnection connString String queryString Sele
  • 在 OSX 上检测 Objective C 或 C++ 中的文件夹访问(如 fs_usage 命令)

    我正在 OSX 上开发实时病毒扫描程序 OSX 的命令行命令fs usage可以通过以下方式确定文件夹访问权限 并且只能以 root 用户身份运行 fs usage w f pathname grep Users Documents Use
  • 用 std::generate_n 填充 std::map

    我想填写一个std map using std generate n但无法让它发挥作用 我尝试过的是这样的事情 unsigned number of pairs 5 std map
  • 对 Action 方法的两个并行 ajax 请求排队,为什么?

    我正在使用 ASP NET MVC 开发一个视频网站 我希望在我的应用程序中拥有的一项功能是转码视频 但由于转码过程可能非常耗时 我想向客户端用户展示该过程的进度 因此 我的架构是使用一个控制器操作来处理整个转码过程 并将其进度写入存储在服
  • C 中的等效 plpgsql 触发器

    我有一个 PostgreSQL 9 0 服务器 并且在某些表上使用继承 因此我必须通过如下触发器模拟外键 CREATE OR REPLACE FUNCTION othertable before update trigger RETURNS
  • 将“C# 友好类型”名称转换为实际类型:“int” => typeof(int)

    我想得到一个System Type给定一个string指定 原始 类型C 友好名称 基本上与 C 编译器读取 C 源代码时的方式相同 我觉得描述我所追求的最好方式是单元测试的形式 我希望存在一种通用技术 可以使以下所有断言通过 而不是尝试对

随机推荐