汉诺塔问题的总结(1)

  1. 首先要知道:对于n个盘子的汉诺塔,最少的移动次数为(2^n-1),在移动过程中会出现2的n次方种不同状态。
  2. 例题一:

题目描述:
n个盘子的汉诺塔问题的最少移动次数是2^/n-1,即在移动过程中会产生2的n次方个系列。由于
发生错移产生的系列就增加了,这种错误是放错了柱子,并不会把大盘放到小盘上,即各柱
子从下往上的大小仍保持如下关系 :
n=m+p+q
a1>a2>…>am
b1>b2>…>bp
c1>c2>…>cq
计算所有会产生的系列总数.


Input:
包含多组数据,首先输入T,表示有T组数据.每个数据一行,是盘子的数
目N<30.
3
1
3
29


Output:
对于每组数据,输出移动过程中所有会产生的系列总数。
3
27
68630377364883

  • 思考:对一个n个盘子的整体来说,有3种状态;将(n-1)个取出,跟最大的一个盘子会有3x2种状态;再将(n-2)个继续取出,跟剩余的两个会有3x3x2种状态……以此类推,可得如下代码:
#include<iostream>
#include<cmath>
using namespace std;
 
int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		long long sum=3;
		cin>>n;
		for(int i=2;i<=n;i++)
			sum+=pow(3,i-1)*2;
		cout<<sum<<endl; 
	}
    return 0;
}
  1. 例题2:

题目描述:
盘子的数目和其中一个盘子的编号,求该盘子移动的最少次数。


Input:
包含多组数据,首先输入T,表示有T组数据.每个数据一行,是盘子的数目N(1<=N<=60)和盘
号k(1<=k<=N)。
2
60 1
3 1


Output:
576460752303423488
4

  • 通过列举,可得出在n个盘子下,编号为k的盘子需要移动的最少次数为2^(n-k)。最明显的例子就是最大的底盘,为2的0次方。这里如果用递归,考虑到有60次,时间消耗将会很大,不合适。代码如下:
#include<iostream>
#include<cmath>
using namespace std;
 
int main()
{
    int n,t,k;
    long long result;
    cin>>n;
    while(n--)
	{
        cin>>t>>k;
        result = pow(2,t-k);
        cout<<result<<endl;
    }
    return 0;
}
  1. 例题3:

问题描述:
现在改变游戏的玩法,不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到下盘的上面。现在有N个圆盘,至少多少次移动才能把这些圆盘从最左边移到最右边?


Input:
包含多组数据,每次输入一个N值(1<=N=35)。
1
3
12


Output:
对于每组数据,输出移动最小的次数。
2
26
531440

  • 思考:多写几组数据,通过观察规律可发现:移动最少次数恰好等于3^n-1,所以代码如下:
#include<iostream>
#include<cmath>
using namespace std;

int main()
{
	int n;
	while(cin>>n)
	{
		long long sum=1;//这里要用long long,不然会溢出
		while(n--) sum*=3;
		cout<<sum-1<<endl; 
	}
	return 0;	
}
  1. 例题4:

题目描述:
不允许直接从最左(右)边移到最右(左)边(每次移动一定是移到中间杆或从中间移出),也不允许大盘放到小盘的上面。如果我们允许最大的盘子放到最上面会怎么样呢?(只允许最大的放在最上面)当然最后需要的结果是盘子从小到大排在最右边。


Input:
输入数据的第一行是一个数据T,表示有T组数据。
每组数据有一个正整数n(1 <= n <= 20),表示有n个盘子。
2
1
10


Output:
对于每组输入数据,最少需要的摆放次数。
2
19684

  • 通过观察数据可得出最少次数满足3^(n-1)+1的规律,可得如下代码:
#include<iostream>
using namespace std;

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		cin>>n;
		long long sum=1;
		n--;
		while(n--) sum*=3;
		cout<<sum+1<<endl;
	}
	return 0;	
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值