您的位置:首页 > 其它

POJ 1958 Strange Towers of Hanoi (四塔问题,线性dp,记忆化搜索)

2014-05-05 21:35 393 查看
题目分析:四柱汉诺塔。由于题目已经给出了求解方法,直接写代码即可。下面总结一下,四塔问题。

感谢这篇文章的作者,点这里就到,总结的很好。直接贴过来~

四塔问题:设有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):







[b]通过这个表达式我们可以知道,k取那个值时f(i)的值,也就是说,不用具体操作,就可以知道移动的最少次数,并且知道k的值,所以在算法实现时,求出k的值是非常重要的。下面的代码就是用来求k的。
[/b]

[b]AC_CODE[/b]



//记忆化搜索
int dp[20];
int Move(int n){
if(dp
!= -1) return dp
;
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
= 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;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: