问题
汉诺塔问题,条件如下:
1、这里有A、B、C和D四座塔。
2、这里有n个圆盘,n的数量是恒定的。
3、每个圆盘的尺寸都不相同。
4、所有的圆盘在开始时都堆叠在塔A上,且圆盘尺寸从塔顶到塔底逐渐增大。
5、我们需要将所有的圆盘都从塔A转移到塔D上。
6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。
请你求出将所有圆盘从塔A移动到塔D,所需的最小移动次数是多少。
输入格式
没有输入
输出格式
对于每一个整数n(1≤n≤12),输出一个满足条件的最小移动次数,每个结果占一行。
输入样例
没有输入
输出样例
参考输出格式
思路
动态规划
我简直弱透了,汉诺塔问题算是递归的入门的经典例子。然鹅一开始却写不出代码来模拟移动过程。
递归版
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根棍子递推求得。
动态规划
- 状态的表示:f[i]
- 初始状态:f[1] = 1
- 转移方程: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;
}