【ACwing 96】奇怪的汉诺塔——区间dp

(题面来自ACwing)

汉诺塔问题,条件如下:

1、这里有A、B、C和D四座塔。

2、这里有n个圆盘,n的数量是恒定的。

3、每个圆盘的尺寸都不相同。

4、所有的圆盘在开始时都堆叠在塔A上,且圆盘尺寸从塔顶到塔底逐渐增大。

5、我们需要将所有的圆盘都从塔A转移到塔D上。

6、每次可以移动一个圆盘,当塔为空塔或者塔顶圆盘尺寸大于被移动圆盘时,可将圆盘移至这座塔上。

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

输入格式

没有输入

输出格式

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

  三个柱子的汉诺塔问题最小步数存在通项公式:2^n - 1,其中n为圆盘数。这个式子很容易由首项a_1 = 1和递推公式a_n = a_(n-1) * 2 + 1得到。递推式的含义是,先利用2个柱子把上面的n-1个圆盘移到B柱上,把第n个圆盘移到C上,再把B柱上的n-1个移到C上。

  四个柱子的汉诺塔问题并不是简单的逐项递推,需要在转移时做出决策。设g[n]为n盘3柱问题的最短步数,f[n]为n盘4柱问题的最短步数,状态转移方程:

   f[i] = min(f[i - j] * 2 + g[j])

   其中j属于[1, i)。这个式子的含义是,我们选择上面的i - j个圆盘,在4柱模式下把它们移到B柱上,然后用其余的3个柱子把剩下的i个圆盘移到D柱上,最后把B柱上的圆盘在4柱模式下移到D柱上。

代码:

  1. #include <cstdio>  
  2. #include <cstring>  
  3. #include <iostream>  
  4. using namespace std;  
  5. int g[20], f[20], ans;  
  6. int main() {  
  7.     for (int i = 1; i <= 12; ++i)  
  8.         g[i] = (1 << i) - 1;  
  9.     puts("1");  //特判1个圆盘
  10.     memset(f, 0x3f, sizeof(f));  
  11.     f[1] = 1;  
  12.     for (int i = 2; i <= 12; ++i) {  
  13.         for (int j = 1; j < i; ++j)  
  14.             f[i] = min(f[i], 2 * f[j] + g[i - j]);  
  15.         printf("%d ", f[i]);  
  16.     }  
  17.     return 0;  
  18. }  
原文地址:https://www.cnblogs.com/TY02/p/11255855.html