河内塔 - 如何不跳过每次递归的挂钩

Posted

技术标签:

【中文标题】河内塔 - 如何不跳过每次递归的挂钩【英文标题】:tower of hanoi - How to not skip over a peg every recursion 【发布时间】:2018-02-11 02:18:26 【问题描述】:

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

规则:

    无法将较大的磁盘堆叠在较小的磁盘上。 一次只能移动一个磁盘。

** 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 步。

谢谢!

【问题讨论】:

您的代码看起来太复杂了。基本的递归算法很简单,将 N 个磁盘从 A 移动到 B,首先将 N-1 个磁盘从 A 移动到 C,将最大的磁盘从 A 移动到 B,将剩余的 N-1 个磁盘从 C 移动到 B。跨度> 看起来与 Modified Towers of Hanoi with 5 pegs n disks 完全相同,可能是相同的分配 【参考方案1】:

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

    将 n-1 叠圆盘移动到第 4 个钉子(或向后移动时第 2 个钉子)

    将第 n 个圆盘移到中间(第 3 个钉子)

    将 n-1 堆栈移回第 2 个挂钩(即后退时第 4 个)

    将第 n 个光盘移动到目标位置

    将 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)

【讨论】:

以上是关于河内塔 - 如何不跳过每次递归的挂钩的主要内容,如果未能解决你的问题,请参考以下文章

河内塔 C++(使用递归)

关于河内塔递归算法时间复杂度的问题

河内塔是什末

河内塔游戏

河内的线性塔

河内塔与 K 钉