多柱汉诺塔问题浅析——算法及公式推导

汉诺塔问题

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

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

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

Frame-Stewart算法

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

#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-1}(N-r) FM1(Nr)继续展开, F M ( N ) F_M(N) FM(N)的推导公式可以改写成如下形式
F M ( N ) = min ⁡ r M , r M − 1 , … , r 3 { 2 [ F M ( r M ) + F M − 1 ( r M − 1 ) + ⋯ + F 3 ( r 3 ) ] + 1 } , s . t . { 0 ≤ r m &lt; N , ∀ m ∈ [ 3 , M ] ∑ m = 3 M r m + 1 = 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&lt;N,\forall m\in[3,M]\\ \sum_{m=3}^M{r_m}+1=N \end{cases} FM(N)=rM,rM1,,r3min{2[FM(rM)+FM1(rM1)++F3(r3)]+1},s.t.{0rm<N,m[3,M]m=3Mrm+1=N
Δ \Delta Δ表示 N N N加一时 F M ( N ) F_M(N) FM(N)的增量,设 Δ F M ( N ) = F M ( N ) − F M ( N − 1 ) \Delta F_M(N)=F_M(N)-F_M(N-1) ΔFM(N)=FM(N)FM(N1),易得
{ Δ F M ( 1 ) = 1 Δ F M ( N + 1 ) = 2 min ⁡ m ∈ [ 3 , M ] { Δ F m ( r m + 1 ) } Δ F M ( N + 1 ) ≥ Δ F M ( N ) \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} ΔFM(1)=1ΔFM(N+1)=2m[3,M]min{ΔFm(rm+1)}ΔFM(N+1)ΔFM(N)
r m + 1 = 1 , ∃ m ∈ [ 3 , M ] r_m+1=1,\exists m\in[3,M] rm+1=1,m[3,M],则 Δ F M ( N + 1 ) = 2 Δ F m ( 1 ) = 2 \Delta F_M(N+1)=2\Delta F_m(1)=2 ΔFM(N+1)=2ΔFm(1)=2。此时 ∑ m = 3 M r m &lt; ∑ m = 3 M 1 = M − 2 &ThickSpace; ⟹ &ThickSpace; N &lt; M − 1 \sum_{m=3}^M{r_m}&lt;\sum_{m=3}^M{1}=M-2\implies N&lt;M-1 m=3Mrm<m=3M1=M2N<M1,将 N + 1 N+1 N+1替换为 N N N,可知
Δ F M ( N ) = 2 ,  if  1 &lt; N ≤ M − 1 \Delta F_M(N)=2, \text{ if }1&lt;N\le M-1 ΔFM(N)=2, if 1<NM1
r m + 1 &gt; 1 , ∀ m ∈ [ 3 , M ] r_m+1&gt;1,\forall m\in[3,M] rm+1>1,m[3,M],且 r m + 1 ≤ m − 1 , ∃ m ∈ [ 3 , M ] r_m+1\le m-1,\exists m\in[3,M] rm+1m1,m[3,M],则 Δ F M ( N + 1 ) = 2 Δ F m ( r m + 1 ) = 4 \Delta F_M(N+1)=2\Delta F_m(r_m+1)=4 ΔFM(N+1)=2ΔFm(rm+1)=4。此时 ∑ m = 3 M r m &lt; ∑ m = 3 M ( m − 1 ) = 1 2 M ( M − 1 ) − 1 &ThickSpace; ⟹ &ThickSpace; N &lt; 1 2 M ( M − 1 ) \sum_{m=3}^M{r_m}&lt;\sum_{m=3}^M(m-1)=\frac{1}{2}M(M-1)-1\implies N&lt;\frac{1}{2}M(M-1) m=3Mrm<m=3M(m1)=21M(M1)1N<21M(M1),将 N + 1 N+1 N+1替换为 N N N,可知
Δ F M ( N ) = 4 ,  if  M − 1 &lt; N ≤ 1 2 M ( M − 1 ) \Delta F_M(N)=4, \text{ if }M-1&lt;N\le\frac{1}{2}M(M-1) ΔFM(N)=4, if M1<N21M(M1)
r m + 1 &gt; m − 1 , ∀ m ∈ [ 3 , M ] r_m+1&gt;m-1,\forall m\in[3,M] rm+1>m1,m[3,M],且 r m + 1 ≤ 1 2 M ( M − 1 ) , ∃ m ∈ [ 3 , M ] r_m+1\le \frac{1}{2}M(M-1),\exists m\in[3,M] rm+121M(M1),m[3,M],则 Δ F M ( N + 1 ) = 2 Δ F m ( r m + 1 ) = 8 \Delta F_M(N+1)=2\Delta F_m(r_m+1)=8 ΔFM(N+1)=2ΔFm(rm+1)=8。此时 ∑ m = 3 M r m &lt; ∑ m = 3 M 1 2 m ( m − 1 ) = 1 6 ( M + 1 ) M ( M − 1 ) − 1 &ThickSpace; ⟹ &ThickSpace; N &lt; 1 6 ( M + 1 ) M ( M − 1 ) \sum_{m=3}^M{r_m}&lt;\sum_{m=3}^M\frac{1}{2}m(m-1)=\frac{1}{6}(M+1)M(M-1)-1\implies N&lt;\frac{1}{6}(M+1)M(M-1) m=3Mrm<m=3M21m(m1)=61(M+1)M(M1)1N<61(M+1)M(M1),将 N + 1 N+1 N+1替换为 N N N,可知
Δ F M ( N ) = 8 ,  if  1 2 M ( M − 1 ) &lt; N ≤ 1 6 ( M + 1 ) M ( M − 1 ) \Delta F_M(N)=8, \text{ if }\frac{1}{2}M(M-1)&lt;N\le\frac{1}{6}(M+1)M(M-1) ΔFM(N)=8, if 21M(M1)<N61(M+1)M(M1)
从上式中找寻规律,由数学归纳法可以证得
Δ F M ( N ) = 2 t ,  if  C M − 3 + t M − 2 &lt; N ≤ C M − 2 + t M − 2 \Delta F_M(N)=2^t, \text{ if }C_{M-3+t}^{M-2}&lt;N\le C_{M-2+t}^{M-2} ΔFM(N)=2t, if CM3+tM2<NCM2+tM2
F M ( N ) = ∑ n = 1 N Δ F M ( n ) F_M(N)=\sum_{n=1}^N{\Delta F_M(n)} FM(N)=n=1NΔFM(n)可知,对于 M = k + 2 M=k+2 M=k+2根柱子、 N N N个圆盘的汉诺塔问题,
F M ( N ) = 1 + ∑ t = 1 T − 1 2 t ( C k + t k − C k − 1 + t k ) + 2 T ( N − C k − 1 + T k ) ,  if  C k − 1 + T k &lt; N ≤ C k + T k 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}&lt;N\le C_{k+T}^{k} FM(N)=1+t=1T12t(Ck+tkCk1+tk)+2T(NCk1+Tk), if Ck1+Tk<NCk+Tk

  • 11
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
汉诺塔问题是一个经典的问题,源于印度一个古老传说。问题是将一根柱子上的64片黄金圆盘按照大小顺序重新摆放到另一根柱子上,且在任何时候,小圆盘上不能放大圆盘,且一次只能移动一个圆盘。 汉诺塔问题的循环算法可以使用迭代的方式来解决。下面是一个示例代码: ```cpp #include <iostream> #include <stack> #include <string> using namespace std; void hanoiTowerIterative(int N, string from, string to, string help) { stack<int> s1, s2, s3; int moves = (1 << N) - 1; for (int i = N; i > 0; i--) { s1.push(i); } if (N % 2 == 0) { swap(s2, s3); } for (int i = 1; i <= moves; i++) { if (i % 3 == 1) { if (s1.empty() || (!s2.empty() && s2.top() < s1.top())) { cout << "Move " << s2.top() << " from " << to << " to " << from << endl; s1.push(s2.top()); s2.pop(); } else { cout << "Move " << s1.top() << " from " << from << " to " << to << endl; s2.push(s1.top()); s1.pop(); } } else if (i % 3 == 2) { if (s1.empty() || (!s3.empty() && s3.top() < s1.top())) { cout << "Move " << s3.top() << " from " << help << " to " << from << endl; s1.push(s3.top()); s3.pop(); } else { cout << "Move " << s1.top() << " from " << from << " to " << help << endl; s3.push(s1.top()); s1.pop(); } } else { if (s2.empty() || (!s3.empty() && s3.top() < s2.top())) { cout << "Move " << s3.top() << " from " << help << " to " << to << endl; s2.push(s3.top()); s3.pop(); } else { cout << "Move " << s2.top() << " from " << to << " to " << help << endl; s3.push(s2.top()); s2.pop(); } } } } int main() { hanoiTowerIterative(3, "A", "B", "C"); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值