汉诺塔II
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 6070 Accepted Submission(s): 2966
Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?
1 3 12
1 5 81
一题比较经典的题;
思路:
首先我们会想到,三柱汉诺塔需要借助另一个柱子存放前n-1个盘子,再把第n个盘子移动到目的位置。
顺其自然的,四柱汉诺塔由于多了一个柱子,我们可以多留下一个盘子n-2,而不让它借位到其他柱子直接移动到目的位置。
算法的基本流程:
(1)从A借助C、D将 n-2个盘子移动到B上。
(2)将第n-2个盘子移动到C上。 (盘子从上到下编号0,1,2,3,4......,n-2,n-1)
(3)将第n-1个盘子移动到D上。
(4)将第n-2个盘子移动到D上。
(5)从B借助A、C将 n-2个盘子移动到D上。
按照以上设计的算法流程,我们得到递归方程:F(n)=2*F(n-2)+3。
因此得到移动步数为:F(n)=4*2^(n/2)-3:n为奇数;F(n)=6*2^(n/2-1)-3:n为偶数。
那到底对不对呢???
经过验证,显然是有问题的。不信你代入n=12 看看结果是什么就知道了。但是不管怎么样有这样的想法思路是好的;
#include<stdio.h>
#include<algorithm>
#define LL unsigned __int64
#define mmax 0x7fffffff
using namespace std;
LL ans[65];
LL ppow(LL a,LL b)
{
LL c=1;
while(b)
{
if(b&1) c=c*a;
a=a*a;
b>>=1;
}
return c;
}
void hanoi()
{
ans[0]=0;
ans[1]=1;
ans[2]=3;
for(int i=3;i<=64;i++)
{
ans[i]=mmax;
for(int x=1;x<i;x++)
{
ans[i]=min(ans[i],(2*ans[x]+ppow(2,i-x)-1));
}
}
}
int main()
{
int n;
hanoi();
while(scanf("%d",&n)!=EOF)
{
printf("%I64u\n",ans[n]);
}
return 0;
}