You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.3 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AcWing 432. Hanoi双塔问题

一.汉若单塔(也称经典汉若塔问题)

首先,我们先画个 n=3 图:

要把 A 柱上的 圆盘 移到 C 柱上,要求无论在哪个柱子上的圆盘都是大的在下面,小的在上面。求从 A 柱上的圆盘移到 C 柱上要多少步?

1. 实践

遇到这种问题,首先想到的是先模拟一次,如下图:

怎么样?看完过程,是不是清晰了许多?全过程是这样的:

步数                 操作        
1 ① A to C
2 ② A to B
3 ① C to B
4 ③ A to C
5 ① B to A
6 ② B to C
7 ① A to C

2. 探索

解释 ① :最上面的第1个圆饼 ② :中间的第2个圆饼 ③ :最下面的第3个圆饼

总共7步。仔细观察我们可以发现,移动的盘子是对称的,如上表:①②①③①②①。 以为点 ,左右对称。再看看右边①②①,也是对称的,这是 n=2 时移动的步数。我们是不是可以推测出如果 n=4 时,①②①③①②①④①②①③①②①是移动顺序呢?事实证明的确如此。移动顺序总是上一个序列加上新的盘子再加上一个序列。

我终于懂了汉诺塔,真是太TM简单了~

由此可得递推公式:

\large f[i] =f[i1] 2+1

刘老师视频讲座

3. 运用

如何运用到c++里面呢?

int f[10010];

int n;
scanf ("%d", &n);
for (int i = 1 ; i <= n ; i++)
    f[i] = f[i-1] * 2 + 1;
printf ("%d\n", f[n]);

这就是主程序。

4. 思考

如何输出中间的步骤?可在评论区回答 or 讨论!

二.汉若双塔

1. 认识

我们来看看汗若双塔长什么样子吧:

他就是每种型号多了1个盘子。移动起来的步骤也就乘2了。

2. 实现

int f[10010];
int n;
scanf ("%d", &n);
for (int i = 1 ; i <= n ; i++)
    f[i] = f[i-1] * 2 + 1;

printf ("%d\n", f[n] * 2);

三.加强

当数据 n<=200 时,我们应该怎么做? answer :当然是 无符号 long long 啦。

NONONO 我们应该开高精度,这才是正解!!!

康康 code

#include <bits/stdc++.h>
using namespace std;

const int N = 100010;

// 加法高精度
int a[N], b[N];
int al, bl;
void add(int a[], int &al, int b[], int &bl) {
    int t = 0;
    al = max(al, bl);
    for (int i = 1; i <= al; i++) {
        t += a[i] + b[i];
        a[i] = t % 10;
        t /= 10;
    }
    if (t) a[++al] = 1;
}

int main() {
    int n;
    cin >> n;
    b[++bl] = 1;

    for (int i = 1; i <= n; i++) {
        add(a, al, a, al);
        add(a, al, b, bl);
    }

    // 最后再乘以2
    add(a, al, a, al);

    for (int i = al; i; i--) cout << a[i];
    return 0;
}