汉诺塔问题
汉诺塔I
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆: 每次只能移动一个圆盘; 大盘不能叠在小盘上面。 提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。问:如何移?最少要移动多少次?
思路:递推式:f(i)=2*f(i-1)+1;
- 将上面的n-1个通过b从a移动c
- 将第n个移到c
- 将n-1个通过a从b移动到c
HDUOJ 1027 诺汉塔II
思路:递推式:f(i)=min(2*f(n-r)+2^r-1),1<=r<i;
- 将上面n-r个圆盘通过c,d移动到b
- 将剩余r个使用三柱法移动到d,即2^r-1
- 将n-r通过a,c移动到d
- 上述求出r的所有取值的最小值为最终解
HDUOJ 2064 汉诺塔III
思路:递推式:f(i)=3*f(i-1)+2
- 首先将i-1个圆盘移动到最右边的柱子
- 第i个圆盘移动到中间
- 前i-1个圆盘移动到最左边
- 第i个圆盘移动到最右边
- 最后将i-1个圆盘移动到最右边
HDUOJ 2077 汉诺塔IV
思路1:
- 设a[i]为将i块圆盘从最左边移动到最右边
- b[i]为将i个圆盘移动到相邻的柱子(移动到相邻的柱子步数相同)
- c[i]为本题的步数
求c[n]:
- 将n-1个圆盘移动到中间柱子
- 将第n个圆盘(最大的圆盘)移动到最右边
- 将中间n-1个圆盘移动到最右边
c[n]=2*b[n-1]+2;
求b[n]:
- 先将n-1个移动到最右边
- 再将第n个移动到中间
- 最后将n-1个从右边移动到中间
b[n]=a[n-1]+b[n-1]+1;
思路2:递推式:f(n)=3*f(n-2)+4;
- 先把n-2个盘子从A通过B移动到C,f(n-2)
- 在把第n-1和第n个盘子从A移动到B,大盘在上,2步
- 再把n-2个盘子从C通过B移动到A,f(n-2)
- 再把第n-1和第n个盘子从B移动到C,2步
- 最后将n-2个盘子从A通过B移动到C,f(n-2)
HDUOJ 1997 汉诺塔VII
思路:
若把n个盘子从A通过B移动到C,则先把n-1个盘子从A移动到B,再把第n个盘子从A移动到C,再把n-1个盘子从B移动到A
所以只需要判断序列是否符合把n个盘子从A移动到C,第n个只能出现在A的底部,或柱子C的底部,否则序列错误
当第n个盘子在A的底部,则继续判断剩下的序列是否把n-1个盘子从A移动到B
当第n个怕你在C的底部,则继续判断剩下的序列是否把n-1个盘子从B移动到C
#include <iostream>
using namespace std;
const int MAX = 65;
int a[MAX], b[MAX], c[MAX];
bool judge(int n, int st[], int ed[], int zh[])
{
if(zh[0]==n) return 0;
else if(st[0]==n) return judge(n-1, st+1, zh, ed);
else if(ed[0]==n) return judge(n-1, zh, ed+1, st);
return 1;
}
int main()
{
int T, N, m, p, q;
cin >> T;
while(T--)
{
cin >> N;
cin >> m;
for(int i=0; i<m; i++)
cin >> a[i];
cin >> p;
for(int i=0; i<p; i++)
cin >> b[i];
cin >> q;
for(int i=0; i<q; i++)
cin >> c[i];
a[m] = b[p] = c[q] = -1;
if(judge(N, a, c, b)) cout << "true" << endl;
else cout << "false" << endl;
}
return 0;
}