1.题目
给定A、B、C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的。
现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:每次只能移动一个圆盘;A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
- Input:每组输入数据为一个正整数n,表示在A柱上放有2n个圆盘。数据规模:对于50%的数据,1<=n<=25;对于100%的数据,1<=n<=200;
- Output:每组输出仅一行,包含一个正整数,为完成上述任务所需的最少移动次数。
2.解题思路
我们做一个比较简单的递推,要把2N个盘从A移动到B上,就先移动2(N-1)个到C上,在移2个到B上。
再把2(N-1)个移到B上,因此F(N)=2*F(N-1)+2
F(1)=2,易得F(N)=2^(N+1)-2
解题思路比我想法更好,描述更清晰的文章很多啊。这里上链接
这篇分析的不错:
【NOIP2007普及组】Hanoi双塔问题 - 腾讯云开发者社区-腾讯云
以下这篇是我见到的分析最好的:
https://www.iteye.com/blog/shmilyaw-hotmail-com-2077098
3. 编程
3.1 使用C++语言
程序
#include<cstring>
#include<iostream>
#include<cstdlib>
using namespace std;
string gaojing(string ,string );
int main()
{
int n;
printf("Please enter a number:");
cin>>n;
string a="2";
string b="2";
for(int i=2;i<=n;++i)
a=gaojing(gaojing(a,a),b);
printf("The least time to complete task:");
cout<<a;
return 0;
}
string gaojing(string a,string b)
{
int js[200];
int a1[200]={0};
int a2[200]={0};
int x=0;
int y=0;
string liehuo;
for(int i=a.size()-1;i>=0;--i)
{
x++;
a1[x]=a[i]-48;
}
for(int j=b.size()-1;j>=0;--j)
{
y++;
a2[y]=b[j]-48;
}
int max=x>y? x:y;
for(int i=1;i<=max+1;++i)
{
js[i]=(a1[i]+a2[i])%10;
a1[i+1]+=(a1[i]+a2[i])/10;
}
for(int i=max+1;i>=1;--i)
{
if(i==max+1&&js[i]==0)
continue;
liehuo+=js[i]+48;
}
return liehuo;
}
测试
C:\Users\zhangyy\CLionProjects\Ctest\cmake-build-debug\Ctest.exe
Please enter a number:8
The least time to complete task:510
Process finished with exit code 0
3.2 使用python语言
既然我们已经推导出公式那就直接套公式。
程序
print("please input a number:")
a = int(input())
print("The least time to complete task is:")
print(2 ** (a + 1) - 2)
测试
C:\Users\zhangyy\PycharmProjects\ACM_Test\venv\Scripts\python.exe C:\Users\zhangyy\PycharmProjects\ACM_Test\main.py
please input a number:
8
The least time to complete task is:
510
Process finished with exit code 0
4.最后
Hanoi塔问题是一个经典的递归问题,它本身的数学复杂度达到了指数函数级别。所以使得运算时间的增长非常快。通过一种递归的思路,首先我们可以总结出一个问题的递归描述方式。然后我们再通过不断的代入和分析,去发现形成等式的规律。这是一种发现递归问题等式描述的方法。为了保证方法最终的正确性,我们还需要经常使用数学归纳法来证明这个等式的正确性。