汉诺塔II
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5900 Accepted Submission(s): 2879
Problem Description
经典的汉诺塔问题经常作为一个递归的经典例题存在。可能有人并不知道汉诺塔问题的典故。汉诺塔来源于印度传说的一个故事,上帝创造世界时作了三根金刚石柱子,在一根柱子上从下往上按大小顺序摞着64片黄金圆盘。上帝命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一回只能移动一个圆盘。有预言说,这件事完成时宇宙会在一瞬间闪电式毁灭。也有人相信婆罗门至今仍在一刻不停地搬动着圆盘。恩,当然这个传说并不可信,如今汉诺塔更多的是作为一个玩具存在。Gardon就收到了一个汉诺塔玩具作为生日礼物。
Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?
Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?
Input
包含多组数据,每个数据一行,是盘子的数目N(1<=N<=64)。
Output
对于每组数据,输出一个数,到达目标需要的最少的移动数。
Sample Input
1 3 12
Sample Output
1 5 81
Author
Gardon
Source
Recommend
分析:3个柱子的汉诺塔来说比较简单,但是当添一个柱子时,思路就稍有不同,参考多住汉诺塔算法设计探究最优的文章,其整体思想就是利用动态规划来解决。
例如,有a,b,c,d四个柱子,
第一步,利用四诺塔方法将a上的r个盘子通过c,d转移到b上共需f[r]步,
然后利用三诺塔将a上n-r个盘子通过d盘移到d上,共需2^(n-r)-1步,
然后将b上的盘子通过a,c柱移到上需要f[r]步,
依据上边规则求出所有
r
(
1
≤
r
≤
n
)情况下步数
f(n)
,取最小值得最终解。
该方法可以推广到多柱汉诺塔。
代码:
理解:本来这道题当看到百度里面多柱汉诺塔的解释后,感觉很简单,但是做时才发现出现了一些问题,一开始用了int 来定义f[n],为了减少时间复杂度,用
f[i]保存2*f[i-j]+pow(2,j)-1的值,这样比较时就会少计算几次,但是这是会发现,当n==64时,会出错。后来改成long long型还是出错,实在不知道原因错在哪,后来搜了一下代码,发现有用double型的,还有用usigned long long 形的,搜了一下范围,后两者范围较大,但是,令人迷惑的是,当n=64时,f[64]的值为18433,数值很小。但是当直接比较的时候就能计算出值,这个原因待以后解决。
错误代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define INF 100000000
__int64 f[10000];
int main()
{
int i,j,n,k;
__int64 t,min;
f[1]=1;f[2]=3;
for(i=3;i<=65;i++)
{
min=INF;
for(j=1;j<i;j++)
{
t=2*f[j]+pow(2,i-j)-1;
if(min>t)
min=t;
}
f[i]=min;
}
while(scanf("%d",&n))
{
//memset(f,0,sizeof(f));
printf("%I64d\n",f[n]);
}
return 0;
}
#include<string.h>
#include<math.h>
#define INF 100000000
__int64 f[10000];
int main()
{
int i,j,n,k;
__int64 t,min;
f[1]=1;f[2]=3;
for(i=3;i<=65;i++)
{
min=INF;
for(j=1;j<i;j++)
{
t=2*f[j]+pow(2,i-j)-1;
if(min>t)
min=t;
}
f[i]=min;
}
while(scanf("%d",&n))
{
//memset(f,0,sizeof(f));
printf("%I64d\n",f[n]);
}
return 0;
}
ac代码:
#include<stdio.h>
#include<string.h>
#include<math.h>
#define INF 1000000000
double f[10000],min;
int main()
{
int i,j,n,k;
f[1]=1;f[2]=3;
for(i=3;i<=64;i++)
{
min=INF;
for(j=1;j<i;j++)
{
f[i]=(2*f[i-j]+pow(2,j)-1);
if(min>f[i])
min=f[i];
}
f[i]=min;
}
while(~scanf("%d",&n))
{
//memset(f,0,sizeof(f));
printf("%.lf\n",f[n]);
}
return 0;
}
#include<string.h>
#include<math.h>
#define INF 1000000000
double f[10000],min;
int main()
{
int i,j,n,k;
f[1]=1;f[2]=3;
for(i=3;i<=64;i++)
{
min=INF;
for(j=1;j<i;j++)
{
f[i]=(2*f[i-j]+pow(2,j)-1);
if(min>f[i])
min=f[i];
}
f[i]=min;
}
while(~scanf("%d",&n))
{
//memset(f,0,sizeof(f));
printf("%.lf\n",f[n]);
}
return 0;
}
657

被折叠的 条评论
为什么被折叠?



