多柱汉诺塔(Matrix上选做题)——递归与动态规划

多柱汉诺塔(Matrix上选做题)——递归与动态规划_第1张图片

分析:
对于三柱汉诺塔问题,我们已经熟知步骤数最优解为 2 i − 1 2^{i}-1 2i1,其中 i 为盘子个数。
对于四柱以上的问题,我们将柱子分为三类,起点柱Start,辅助柱Buf,终点柱End,三柱情况时,我们总想着将前n - 1个盘从Start借助End移动到Buf,然后将第 n 个盘从Start移到End,最后将Buf柱上的n - 1个盘借助Start移到End,这就找到了递推关系:
S t e p s ( n ) = 2 ∗ S t e p s ( n − 1 ) + 1 Steps(n) = 2*Steps(n-1)+1 Steps(n)=2Steps(n1)+1
对于三柱问题,我们将前n-1盘移到Buf是唯一的选择,对于四柱以上的问题,我们可以移前n-1或者前n-2等等,哪个最佳呢?这就需要动态规划了。
思路:
这里提供Frame算法:
由于不知道哪个 r 使得移动前 n - r 个盘是最优解,我们需要算出所有可能性再取最小值。

(1)首先把前 n - r 个盘移从Strat移到Buf上,此时可用柱数为 m ,步骤数是 S t e p s ( m , n − r ) Steps(m,n-r) Steps(m,nr)

(2)再将剩下的 r 个盘从Start移到End上,由于上述步骤占用了1根柱子步骤数是 S t e p s ( m − 1 , r ) Steps(m - 1,r) Steps(m1r)

(3)最后将第一步的 n - r 个盘从Buf移到End上,虽然End柱被占用,但其中的盘均比这 n - r 个大,故可用柱子数仍为 m ,步骤数是 S t e p s ( m , n − r ) Steps(m,n-r) Steps(mnr)

(4)依据上边规则求出所有 r ( 1 ≤ r ≤ n ) r(1≤r≤n) r1rn情况下步数,取最小值得最终解。

因此Frame算法的递归方程如下:

S t e p s ( m , n ) = m i n ( 2 ∗ S t e p s ( m , n − r ) + S t e p s ( m − 1 , r ) ) , ( 1 ≤ r ≤ n ) 。 Steps(m,n)=min(2*Steps(m,n-r)+Steps(m-1,r)),(1≤r≤n)。 Steps(m,n)=min(2Steps(m,nr)+Steps(m1,r))1rn

于是有下列代码:

#include 
#include 

long long min_steps(int m,int n);

long long min(long long a,long long b);

int main() {
	int m,n;
	scanf("%d %d",&m,&n);
	printf("%lld\n",min_steps(m,n));
} 
long long min_steps(int m,int n) {
	
	if(n == 0) return 0;//若盘子数为0,无论柱子数为多少,移动步数都是0
	if(n == 1) return 1;//若盘子数为1,无论柱子数为多少,移动步数都是1
	if(n == 2) return 3;//若盘子数为2,无论柱子数为多少,移动步数都是2
	
	if(m == 3) return (long long)pow(2,n) - 1;//若柱子数为3,就是经典的三柱汉诺塔问题
	
	else if(m > 3){//四柱及以上汉诺塔问题
		long long mini = (long long)pow(2,30);//预设一个比较大的值,方便下面取最小值不出错
		for(int i = 1;i <= n;i ++) {	
			mini = min(mini,2*min_steps(m,n-i)+min_steps(m-1,i));
		}//动态规划
		return mini;
	}
} 
long long min(long long a,long long b) {
	if(a <= b) return a;
	else return b;
}

你可能感兴趣的:(编程趣题)