汉诺塔Ⅲ
题目链接:
题目:
汉诺塔III
时间限制:1000/1000 MS(Java / Others)内存限制:32768/32768 K(Java / Others)现在我们改变游戏的玩法,不允许直接从最左(右)移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面
.Daisy已经做过原来的汉诺塔问题和汉诺塔II,但碰到这个问题时,她想了很久都不能解决,现在请你帮助她。现在有ñ个圆盘,她至少多少次移动才能把这些圆盘从最左边移到最右边?
题目分析:
题目大意:
将最左边杆上n个自上而下,由小到大的盘移到最右边杆上,要求:不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。
思路:
我们令将n个盘从A-> B需要一个(n)步。
下面分三步进行:
将n-1个盘从A - > B - > C,需要一个(n-1)步将第n个盘从A->B,再将n-1个盘从C ->B ->A,需要一个(n-1)+ 1步
将第n个盘从B -> C,再将n-1个盘从A -> B -> C,需要1 + a(n-1)步
所以a(n)= 3 * a(n-1)+ 2步。
注意数据范围。
AC代码:
#include <stdio.h>
int main()
{
int n,i;
long long a[40]= {0,2};
for (i=2; i<=35; i++)
a[i]=3*a[i-1]+2;
while(~scanf("%d",&n))
printf("%lld\n",a[n]);
return 0;
}
我看到有人说有通项公式f(n)= 3 ^ n - 1,结果试了一下提交发现WA了,于是对比了两个数据
将不同的地方打印出来了:
a(21)= 10460353202 f(21)= 10460353201
a(25)= 847288609442 f(25)= 847288609441
a(23)= 94143178826 f(23)= 94143178825a(27)= 7625597484986 f(27)= 7625597484985
a( 29)= 68630377364882 f(29)= 68630377364881
a(31)= 617673396283946 f(31)= 617673396283945
a(33)= 5559060566555522 f(33)= 5559060566555521
a(35)= 50031545098999706 f(35)= 50031545098999705
汉诺塔Ⅳ
题目链接:
题目:
汉诺塔IV
时间限制:1000/1000 MS(Java / Others)内存限制:32768/32768 K(Java / Others)每组数据有一个正整数N(1 <= N <= 20),表示有个盘子。
题目分析:
题目大意:
与汉诺塔Ⅲ相比,它多了一个条件:允许最大的盘子放到最上面(只允许最大的放在最上面),其余条件不变。
思路:
先将上面n-1个盘子从A - > B,需要一个(n-1)步
再将第n个盘子从A→B→C,需要2步
最后将n-1个盘子从BC,需要一个第(n-1)步
所有相对于汉诺塔Ⅲ,A(n)= a(n-1)+2,在题目范围内可以用通项公式f(n)= 3 ^ n - 1
AC代码:
(1)利用公式:A(n)= a(n-1)+2
#include <stdio.h>
int main()
{
int n,m,i;
long long a[25]= {0,2};
for (i=2; i<=20; i++)
a[i]=3*a[i-1]+2;
scanf("%d",&n);
while(n--)
{
scanf("%d",&m);
printf("%lld\n",a[m-1]+2);
}
}
(2)利用通项公式:f(n)= 3 ^ n - 1
#include <stdio.h>
#include <math.h>
int main()
{
int n,m,i;
long long a;
scanf("%d",&m);
while(m--)
{
scanf("%d",&n);
a=pow(3,n-1)+1;
printf("%lld\n",a);
}
return 0;
}