汉诺塔II
Gardon是个怕麻烦的人(恩,就是爱偷懒的人),很显然将64个圆盘逐一搬动直到所有的盘子都到达第三个柱子上很困难,所以Gardon决定作个小弊,他又找来了一根一模一样的柱子,通过这个柱子来更快的把所有的盘子移到第三个柱子上。下面的问题就是:当Gardon在一次游戏中使用了N个盘子时,他需要多少次移动才能把他们都移到第三个柱子上?很显然,在没有第四个柱子时,问题的解是2^N-1,但现在有了这个柱子的帮助,又该是多少呢?
1 3 12
1 5 81
/*
分析:设F[n]为所求的最小步数,显然,当n=1时,F[n]=1;当n=2时,F[n]=3;如同经典汉诺塔一样,
我们将移完盘子的任务分为三步:
(1)将x(1<=x<=n)个盘从a柱依靠b,d柱移到c柱,这个过程需要的步数为F[x];
(2)将a柱上剩下的n-x个盘依靠b柱移到d柱(注:此时不能够依靠c柱,因为c柱上的所有盘都比a柱
上的盘小) (典型的汉诺塔就是一共3个柱子,依靠一个柱子挪到第三个的过程,公式是2^n-1)
移动方式相当于是一个经典汉诺塔,即这个过程需要的步数为2^(n-x)-1
(3)将c柱上的x个盘依靠a,b柱移到d柱上,这个过程需要的步数为F[x];
任务完成。
故完成任务所需要的总的步数F[n]=F[x]+2^(n-x)-1+F[x]=2*F[x]+2^(n-x)-1;
但这还没有达到要求,题目中要求的是求最少的步数,易知上式,随着x的不同取值,对于同一个n,
也会得出不同的F[n]。即实际该问题的答案应该min{2*F[x]+2^(n-x)-1},其中1<=x<=n;
在用高级语言实现该算法的过程中,我们可以用循环的方式,遍历x的各个取值,
并用一个标记变量min记录x的各个取值中F[n]的最小值。
典型的汉诺塔的公式是2^n-1 。迭代公式是f(x)=2f(x-1)+1
*/
#include<stdio.h>
#include<math.h>
int main()
{
int n,f[66];//一个柱子上的盘子依靠两个柱子移动到第四个柱子上所用的步数
f[1]=1;
f[2]=3;
for(int i=3;i<=65;i++) //实质上是打表
{
int min=99999999;
for(int x=1;x<i;x++)
{
if (2*f[x] + pow(2.0,i-x) -1 <min) min=2*f[x] + pow(2.0,i-x)-1;
}
f[i]=min;
}
while(~scanf("%d",&n)) //不要把表打在while(n--)里面,否则每个n都要执行一次,肯定会超时
{
printf("%d\n",f[n]);
}
return 0;
}
汉诺塔III
现在我们改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。
Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有N个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?
1 3 12
2 26 531440
/*
分析:要想把第n个盘从1移到3,需要3个步骤 :
1.)把前n-1个从1移动3 .
2.)第n个盘要从1->2->3经历2步.
3.)而前n-1个盘需要先 3->1 ( 这是为了给 第n个盘让路 ), 最后再 1->3。
∴f(n) = 3 × f(n-1) + 2;
f(1) = 2;
这样我们就得到了这一题的递推公式, 当然我们可以做进一步的优化 , 优化方法如下:
f(n) = 3 *f(n-1) + 2
f(1) = 2
=>
f(n) + 1 = 3 × [f(n-1) + 1]
=>
f(n) = 3n - 1
*/
#include<stdio.h>
#include<math.h>
__int64 han(int n) //double位数不够__int64用,所以WA
{
return pow(3.0,n)-1; //返回值是double型
}
int main()
{
int t;
while(~scanf("%d",&t))
{
printf("%I64d\n",han(t));
}
return 0;
}
#include<stdio.h>
#include<math.h>
int main()
{
int t;
while(~scanf("%d",&t))
{
__int64 a=1;
for(int b=0;b<t;b++) //只好这样写了
a=a*3;
printf("%I64d\n",a-1);
}
return 0;
}