题目分析:四柱汉诺塔。由于题目已经给出了求解方法,直接写代码即可。下面总结一下,四塔问题。
感谢这篇文章的作者,点这里就到,总结的很好。直接贴过来~
四塔问题:设有A,B,C,D四个柱子(有时称塔),在A柱上有由小到大堆放的n个盘子。
今将A柱上的盘子移动到D柱上去。可以利用B,C柱作为工作栈用,移动的规则如下:
①每次只能移动一个盘子。
②在移动的过程中,小盘子只能放到大盘子的上面。
设计并实现一个求解四塔问题的动态规划算法,并分析时间和空间复杂性。
算法思想:
用如下算法移动盘子(记为FourPegsHanoi):
1)、将A柱上n个盘子划分为上下两部分,下方部分共有k(1≤k≤n)个盘子,上方部分共有n - k个盘子。
2)、将A柱上面部分n–k个盘子使用FourPegsHanoi算法经过C、D柱移至B柱。
3)、将A柱剩余的k个盘子使用ThreePegsHanoi算法经过C柱移至D柱。
4)、将B柱上的n–k个盘子使用FourPegsHanoi算法经过A、C柱移至D柱。
ThreePegsHanoi算法如下(设三个柱子分别为A、B、C,A柱上共有k个盘子):
1)、将A柱上方k-1个盘子使用ThreePegsHanoi算法经过B柱移至C柱。
2)、将C柱上最后一个盘子直接移至C盘。
3)、将B柱上k-1个盘子使用ThreePegsHanoi算法经过A柱移至C柱。
算法步骤:
根据动态规划的四个步骤,求解如下:
1)、最优子结构性质:
四柱汉诺塔问题的最优解是用最少的移动次数将A柱上的盘子全部移到D柱上。当盘子总数为i时,我们不妨设使用FourPegsHanoi的最少移动次数为f(i)。相应的ThreePegsHanoi 算法移动次数为g(k),由于g(k)=2g(k-1)+1=pow(2,k) -1,当k确定时,g(k)也是不变的。
f(i)为最优解时,其子问题f(i-k)也必为最优解。如果f(i-k)不是最优解,那么存在f’(i-k) < f(i-k)。用f’(i-k)替换f(i-k)将产生一个比f(i)更优的解。这与f(i)为最优解是矛盾的。所以本问题具有最优子结构性质。
2)、递归地定义问题的最优解:
根据上述FourPegsHanoi算法得到最少移动次数f(i):
通过这个表达式我们可以知道,k取那个值时f(i)的值,也就是说,不用具体操作,就可以知道移动的最少次数,并且知道k的值,所以在算法实现时,求出k的值是非常重要的。下面的代码就是用来求k的。
AC_CODE
//记忆化搜索 int dp[20]; int Move(int n){ if(dp[n] != -1) return dp[n]; int s = 1<<30; for(int i = 1;i <= n;i++){ s = min(s , 2 * Move(n - i) + (int)pow(2.0 , 1.0*i) - 1); } return dp[n] = s; } int main() { //freopen("in.txt","r",stdin); int i , j , k; for(i = 1;i <= 12;i++){ memset(dp , -1 , sizeof(dp)); dp[1] = 1; dp[0] = 0; cout << Move(i) << endl; } return 0; }
//线性dp int dp[20]; int main() { //freopen("in.txt","r",stdin); int i , j , k; for(i = 0;i <= 13;i++) dp[i] = inf; dp[1] = 1; dp[0] = 0; for(i = 1;i <= 12;i++){ for(j = 1;j <= i;j++) dp[i] = min(dp[i] , 2*dp[i - j] + (int)pow(2.0 , 1.0*j) - 1); } for(i = 1;i <= 12;i++){ cout << dp[i] << endl; } return 0; }
POJ 1958 Strange Towers of Hanoi (四塔问题,线性dp,记忆化搜索)