在做UVA10795新汉诺塔问题前,我决定先去把汉诺塔给熟悉一下。
我还没做过呢T T
第一次接触汉诺塔貌似是谭浩强的C语言里面的递归。(小小吐槽一下他的书)
言归正传,
这题与常规的不一样在于:不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出)
先回想一下常规的题:(允许直接从A到C)
从左到右设为A、B、C,因为可以直接从A移动到C,所以只需要N-1到B,N到C,要达到目的还要N-1到C(这里N指第N个盘子,N-1指1~N-1个盘子,下同)
它的递推式为:
a[1] = 1;
a[n] = a[n-1] * 2 + 1;
可以验证:
a[n]= 2^n-1;
这题呢?其实也很简单,同样的,从左到右设为A、B、C因为不能从A直接移动到C,那么把第N个盘子移动到C时,必有N在B,所以把N-1个盘子移动到C之后,还要移动回A。
那么就是这样N-1移动到C,N到B,N-1到A,N到C,N-1到C
显然,它的递推式为:
a[1] = 2;
a[n] = a[n-1] *3 + 2;
注意上下两个的对比。
然后我就猜想:
a[n]= 3^n-1?
答案是肯定的。
用数学归纳法证明如下:
1. n=1是显然成立
2. 设n=k时,等式成立;那么有a[k]= 3^k-1 a[k]=a[k-1]*3+2
3. n=k+1时a[k+1]=a[k]*3+2=(3^k-1) *3+2=3^(k+1)-3+2=3^(k+1)-1
证毕:)
所以代码如下:(HDU不支持%lld好吧。。。难道是我抛弃VC6的后果么,换个OJ各种悲T T)
PS(用pow WA的原因在于 double可表示的范围比long long 小)
#include <iostream>
using namespace std;
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
long long x=1;
for(int i=0;i<n;i++)
x*=3;
printf("%I64d\n",--x);//HDU不支持lld么。。
//cout<<--x<<endl;
}
}