一、题目
3-7四柱汉诺塔问题
四柱汉诺塔要求同三柱汉诺塔,只不过多了一个辅助柱子。计算n个盘子由a柱借助c和d柱移动到b柱上的最少移动次数。
如图:
二、分析
1、分析最优子结构性质
该问题可将a柱上的n个盘子分为上下两部分,下半部分k个盘子,上半部分n-k个盘子。
移动步骤如下∶
(1)将a柱前n-k个盘子借助b,c移动到d ( n-k个盘子四柱汉诺塔问题)
(2)将a柱剩余的k个盘子借助c移动到b ( k个盘子的三柱汉诺塔问题)
(3)将d柱n-k个盘子借助a、c柱移动到b ( n-k个盘子四柱汉诺塔问题)
由此可见:
n个盘子的四柱汉诺塔问题可转化为2个n-k个盘子的四柱汉诺塔问题和1个k个盘子三柱汉诺塔问题(移动次数已知为2^k-1)。
因此该问题满足最优子结构性质。即大问题的最优解包含子问题的最优解。
2、最少移动次数的递归定义
设n个盘子的四柱汉诺塔的最少移动次数为f(n )
(1)当n=0时,移动次数为0
(2)当n=1时,移动次数为1
(3)当n>1时,f (n ) =2f ( n-k ) +2^k-1 在0<k<n范围的最小值
3、求最优值-时间复杂性O(n2)
int Fn(int n){
f[0]=0;//0个盘子移动次数是0
f[1]=1;//1个盘子移动次数是1
for(int i=2;i<=n;i++){ //把盘子数i从2加到n
f[i]=2*f[i-1]+1; //把盘子数分为i-1和1 ,初始化f[i]=2*f[i-1]+1
for(int k=2;k<i;k++){ //盘子数分为i-k和k
int t=2*f[i-k]+exp2(k)-1;
if(t<f[i])
f[i]=t;
}
}
}
三、代码
//3-7四柱汉诺塔问题 (动态规划)
#include<iostream>
#include<math.h>
#include<algorithm>
using namespace std;
int f[100];//f[i]是四个柱子下i个盘子移动的次数
//四柱汉诺塔问题: a上面有n个盘子,有a,b,c,d四个个柱子,要求把a上面的n个盘子移到b上
int Fn(int n){
f[0]=0;//0个盘子移动次数是0
f[1]=1;//1个盘子移动次数是1
for(int i=2;i<=n;i++){ //把盘子数i从2加到n
f[i]=2*f[i-1]+1; //把盘子数分为i-1和1 ,初始化f[i]=2*f[i-1]+1
for(int k=2;k<i;k++){ //盘子数分为i-k和k
int t=2*f[i-k]+exp2(k)-1;
if(t<f[i])
f[i]=t;
}
}
}
int cnt=0;//记录移动次数
//顺便复习一下 三柱汉诺塔问题 (递归)
// a上面有n个盘子,有a,b,c三个柱子,要求把a上面的n个盘子移到b上
void hanoi(int n,int a,int b,int c){//三柱汉诺塔问题 n个盘子的移动次数是2^n-1
if(n>0){
hanoi(n-1,a,c,b); //把a上面的n-1个盘子移到c上面
cnt++;// move(a,b); 把a上面的最后一个盘子移到b上
hanoi(n-1,c,b,a); //把c上面的n-1个盘子移到b上面
}
else return;
}
int main(){
int n;//n个盘子
int a=0,b=0,c=0;
//cin>>n;
n=4;
Fn(n);
cout<<n<<"个盘子,四柱移动次数是"<<f[n]<<endl;
a=n;
hanoi(n,a,b,c);
cout<<n<<"个盘子,三柱移动次数是"<<cnt<<endl;
return 0;
}