分享

多柱汉诺塔问题浅析

 dinghj 2019-09-21

汉诺塔问题

汉诺塔(Tower of Hanoi)是一个数学游戏:有三根柱子,其中一根柱子自底向上串着尺寸渐小的多个圆盘,遵循以下规则:
1、一次只能移动一个圆盘;
2、大圆盘不能放在小圆盘上面。
请问最少需要移动多少步,才能将所有圆盘移到另一根柱子上?

解答: 设移动 N个圆盘所需的最少步数为 F(N)。将三根柱子分别命名为A、B、C,要把 N个圆盘从A柱移至C柱,拆解为如下步骤:
1、将 N-1个圆盘从A柱移至B柱,需要 F(N-1)步;
2、将余下的最大圆盘从A柱移至C柱,需要一步;
3、将 N-1个圆盘从B柱移至C柱,需要 F(N-1)步。
得到最少移动步数的递推公式 F(N)=2F(N-1)+1。易知 F(1)=1,可得通项公式 F(N)=2^N-1

推广: 如果有四根或者更多柱子,所需的最少移动步数又是多少?

Frame-Stewart算法

该算法采用递推的思想来求解多柱汉诺塔问题。设 M根柱子、 N个圆盘所需的最少移动步数为 F_M(N),将移动步骤拆解为:
1、将 r个圆盘移到另一根柱子上(非目标柱),需要 F_M(r)步;
2、将余下的 N-r个圆盘移至目标柱,需要 F_{M-1}(N-r)步;
3、将 r个圆盘移至目标柱,需要 F_M(r)步。
得到递推公式
F_M(N)=\min\limits_{1\le r<N}\{2F_M(r)+F_{M-1}(N-r)\}
代码:

#include <iostream>
#include <math.h>
#include <map>
using namespace std;

// the least number of movements for n disks, m pegs
map<pair<int, int>, double> mapLeastMoves;
double LeastMoves(const int n, const int m) {
    if (n < 0 || m < 3)
        return -1;
    if (n == 1)
        return 1;
    const auto index = make_pair(n, m);
    if (mapLeastMoves.count(index) > 0)
        return mapLeastMoves[index];
    double least_moves;
    if (m == 3) {
        least_moves = pow(2., n) - 1;
    } else {
        least_moves = 2 * LeastMoves(n - 1, m) + LeastMoves(1, m - 1);
        for (int r = n - 2; r > 0; --r) {
            double moves = 2 * LeastMoves(r, m) + LeastMoves(n - r, m - 1);
            if (moves < least_moves)
                least_moves = moves;
            else // a little optimization
                break;
        }
    }
    mapLeastMoves[index] = least_moves;
    return least_moves;
}

void main() {
    int M = 7, N = 10;
    cout << "M\\N";
    for (int n = 1; n <= N; ++n)
        cout << "\tN = " << n;
    cout << endl;
    for (int m = 3; m <= M; ++m) {
        cout << "M = " << m;
        for (int n = 1; n <= N; ++n)
            cout << "\t" << LeastMoves(n, m);
        cout << endl;
    }
    system("pause");
}

输出:

M\N     N = 1   N = 2   N = 3   N = 4   N = 5   N = 6   N = 7   N = 8   N = 9   N = 10
M = 3   1       3       7       15      31      63      127     255     511     1023
M = 4   1       3       5       9       13      17      25      33      41      49
M = 5   1       3       5       7       11      15      19      23      27      31
M = 6   1       3       5       7       9       13      17      21      25      29
M = 7   1       3       5       7       9       11      15      19      23      27

多柱情形下的通项公式

F_{M-1}(N-r)继续展开, F_M(N)的推导公式可以改写成如下形式
F_M(N)=\min\limits_{r_M,r_{M-1},\dots,r_3}\{2[F_M(r_M)+F_{M-1}(r_{M-1})+\dots+F_3(r_3)]+1\},\\s.t.\quad\begin{cases}0\le r_m<N,\forall m\in[3,M]\\\sum_{m=3}^M{r_m}+1=N\end{cases}
\Delta表示 N加一时 F_M(N)的增量,设 \Delta F_M(N)=F_M(N)-F_M(N-1),易得
\begin{cases}\Delta F_M(1)=1\\\Delta F_M(N+1)=2\min\limits_{m\in[3,M]}\{\Delta F_m(r_m+1)\}\\\Delta F_M(N+1)\ge\Delta F_M(N)\end{cases}
r_m+1=1,\exists m\in[3,M],则 \Delta F_M(N+1)=2\Delta F_m(1)=2。此时Unexpected text node: '&ThickSpace;',将 N+1替换为 N,可知
\Delta F_M(N)=2, \text{ if }1<N\le M-1
r_m+1>1,\forall m\in[3,M],且 r_m+1\le m-1,\exists m\in[3,M],则 \Delta F_M(N+1)=2\Delta F_m(r_m+1)=4。此时Unexpected text node: '&ThickSpace;',将 N+1替换为 N,可知
\Delta F_M(N)=4, \text{ if }M-1<N\le\frac{1}{2}M(M-1)
r_m+1>m-1,\forall m\in[3,M],且 r_m+1\le \frac{1}{2}M(M-1),\exists m\in[3,M],则 \Delta F_M(N+1)=2\Delta F_m(r_m+1)=8。此时Unexpected text node: '&ThickSpace;',将 N+1替换为 N,可知
\Delta F_M(N)=8, \text{ if }\frac{1}{2}M(M-1)<N\le\frac{1}{6}(M+1)M(M-1)
从上式中找寻规律,由数学归纳法可以证得
\Delta F_M(N)=2^t, \text{ if }C_{M-3+t}^{M-2}<N\le C_{M-2+t}^{M-2}
F_M(N)=\sum_{n=1}^N{\Delta F_M(n)}可知,对于 M=k+2根柱子、 N个圆盘的汉诺塔问题,
F_M(N)=1+\sum_{t=1}^{T-1}{2^t(C_{k+t}^k-C_{k-1+t}^k)}+2^{T}(N-C_{k-1+T}^k), \text{ if }C_{k-1+T}^{k}<N\le C_{k+T}^{k}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多