【题解】AcWing 96.奇怪的汉诺塔

AcWing 96.奇怪的汉诺塔

题目描述

汉诺塔问题,条件如下:

  1. 这里有 A 、 B 、 C A、B、C ABC D D D 四座塔。
  2. 这里有 n n n 个圆盘, n n n 的数量是恒定的。
  3. 每个圆盘的尺寸都不相同。
  4. 所有的圆盘在开始时都堆叠在塔 A A A 上,且圆盘尺寸从塔顶到塔底逐渐增大。
  5. 我们需要将所有的圆盘都从塔 A A A 转移到塔 D D D 上。
  6. 每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。

请你求出将所有圆盘从塔 A A A 移动到塔 D D D,所需的最小移动次数是多少。

输入格式

没有输入

输出格式

对于每一个整数 n n n,输出一个满足条件的最小移动次数,每个结果占一行。

数据范围

1 ≤ n ≤ 12 1≤n≤12 1n12

题目分析

对于最典型的三塔汉诺塔问题,我们知道 f [ i ] = 2 f [ i − 1 ] + 1 f[i]=2f[i-1]+1 f[i]=2f[i1]+1

其实,我们可以将这种想法用于任意塔数的汉诺塔问题。不妨设现有 k k k 座塔, n n n 个圆盘,在有 i i i 座塔时移动 j j j 个圆盘所需最少步数为 f i [ j ] f_i[j] fi[j]。很明显,我们要求的就是 f k [ n ] f_k[n] fk[n]

我们先把前 i i i 个圆盘在 k k k 座塔的模式下移动到第 2 2 2 座塔上,再将剩下 n − i n-i ni 个圆盘在 k − 1 k-1 k1 座塔的模式下移动到第 3 3 3 座塔上,最后第 2 2 2 座塔的 i i i 个圆盘在 k k k 座塔的模式下移动到第 3 3 3 座塔上。在移动的过程中,我们并不需要知道这些圆盘是如何移动过去的,我们只需要知道用这些移动圆盘的方法如何递推到移动更多圆盘的方法。因此, f k [ n ] = m i n ( 2 ∗ f k [ i ] + f k − 1 [ n − i ] ) f_k[n]=min(2*f_k[i]+f_{k-1}[n-i]) fk[n]=min(2fk[i]+fk1[ni])。初始状态: f i [ 1 ] = 1 f_i[1]=1 fi[1]=1

如果还是不能理解汉诺塔的递推和递归,这篇回答通过“十个土著搬盘子”的故事形象地解释了这个问题 (结局很妙,淡出递归其实都是一个函数,只是参数不同,干的事不同罢了)。

回到题目,四座塔的汉诺塔就显得十分简单了: f 4 [ n ] = m i n ( 2 ∗ f 4 [ i ] + f 3 [ n − i ] ) f_4[n]=min(2*f_4[i]+f_3[n-i]) f4[n]=min(2f4[i]+f3[ni])

代码:

#include <iostream>
#include <cstring>
using namespace std;

const int N = 15;
int f[N], d[N];

int main(){
    
    
    memset(f, 0x3f, sizeof(f));
    d[1] = 1, f[1] = 1;
    
    for (int i = 2; i <= 12; i ++)
        d[i] = d[i - 1] * 2 + 1;
    
    for (int i = 2; i <= 12; i ++)
        for (int j = 1; j < i; j ++)
            f[i] = min(f[i], 2 * f[j] + d[i - j]);
    
    for (int i = 1; i <= 12; i ++)
        cout << f[i] << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/f4u4u4r/article/details/117961456
今日推荐