奇怪的汉诺塔

问题

汉诺塔问题,条件如下:
1、这里有A、B、C和D四座塔。
2、这里有n个圆盘,n的数量是恒定的。
3、每个圆盘的尺寸都不相同。
4、所有的圆盘在开始时都堆叠在塔A上,且圆盘尺寸从塔顶到塔底逐渐增大。
5、我们需要将所有的圆盘都从塔A转移到塔D上。
6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。
请你求出将所有圆盘从塔A移动到塔D,所需的最小移动次数是多少。

输入格式

没有输入

输出格式

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

输入样例

没有输入

输出样例

参考输出格式

思路

动态规划

关于dp

我简直弱透了,汉诺塔问题算是递归的入门的经典例子。然鹅一开始却写不出代码来模拟移动过程。
递归版

void move(int n)
{
    if (n == 1) 
    {
        cnt++;
        return;
    }
    move(n-1);
    move(1);
    move(n-1);
}

递推版

for (int i = 1; i <= 12; i++) //递推计算i个盘子3根棍子的情况
{
    d[i] = d[i-1]*2 + 1; //将n-1个盘子挪到第2根棍子上,接着将第n个盘子挪到第3根棍子,最后将n-1个盘子也挪到第3根棍子
}

4根棍子的汉诺塔玩法:先将j个盘子放到一根棍子上,接着将第i-j个盘子挪到第4根棍子。由于j个盘子的那跟棍子不能再放,故此时为3根棍子的情形,故有d[i-j]次挪动。最后再将j个盘子也挪到第4根棍子。

f[i]为i次移动中的最小值:f[i] = min(f[i], f[j]*2 + d[i-j]);

综上可得,n根棍子的汉诺塔,可由n-1根棍子递推求得。

动态规划

  1. 状态的表示:f[i]
  2. 初始状态:f[1] = 1
  3. 转移方程:f[i] = min(f[i], f[j]*2 + d[i-j])

代码

知识积累

数组定义为全局变量,初始化为0
将f数组初始化为大值0x3f,sizeof在编译期间运行: memset(f, 0x3f, sizeof f);

调试过程

1.递推初值f[0]为0
2.j从0开始枚举
#include <iostream>
#include <cstring>
using namespace std;

int d[15], f[15]; //定义为全局变量,初始化为0

int main()
{
    for (int i = 1; i <= 12; i++) //递推计算i个盘子3根棍子的情况
    {
        d[i] = d[i-1]*2 + 1; //将n-1个盘子挪到第2根棍子上,接着将第n个盘子挪到第3根棍子,最后将n-1个盘子也挪到第3根棍子
    }
    memset(f, 0x3f, sizeof f); //将f数组初始化为大值0x3f,sizeof在编译期间运行
    f[0] = 0; //递推初值f[0]为0
    for (int i = 1; i <= 12; i++) //递推计算i个盘子4根棍子的情况
    {
        //从0开始枚举,表示只用到3根棍子,j < i
        for (int j = 0; j < i; j++) f[i] = min(f[i], f[j]*2 + d[i-j]); //先将j个盘子放到一根棍子上,接着将第i-j个盘子挪到第4根棍子,最后将j个盘子也挪到第4根棍子
    }
    for (int i = 1; i <= 12; i++) cout << f[i] << endl;
}