1. 程式人生 > >HDU - 1995 奇妙的塔 (漢諾塔遞迴思想詳解)

HDU - 1995 奇妙的塔 (漢諾塔遞迴思想詳解)

用1,2,...,n表示n個盤子,稱為1號盤,2號盤,...。號數大盤子就大。經典的漢諾塔問 
題經常作為一個遞迴的經典例題存在。可能有人並不知道漢諾塔問題的典故。漢諾塔來源於 
印度傳說的一個故事,上帝創造世界時作了三根金剛石柱子,在一根柱子上從下往上按大小 
順序摞著64片黃金圓盤。上帝命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱 
子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一回只能移動一個圓盤。我們 
知道最少需要移動2^64-1次.在移動過程中發現,有的圓盤移動次數多,有的少 。 告之盤 
子總數和盤號,計算該盤子的移動次數.

 

Input

包含多組資料,首先輸入T,表示有T組資料.每個資料一行,是盤子的數目N(1<=N<=60)和盤 
號k(1<=k<=N)。 

 

Output

對於每組資料,輸出一個數,到達目標時k號盤需要的最少移動數。 

 

Sample Input

2
60 1
3 1

 

Sample Output

576460752303423488
4

解題思路:找到遞推公式就好做了,首先我們看下漢諾塔遞迴的思想,設A柱上最初有n個盤子,當n==1時,只需將編號為1的盤子從塔座A直接移動到塔座C上即可,否則執行以下三步:

步驟1)   用C柱做過渡,將A柱上n-1個盤子移到B柱上

步驟2)將A柱上最後一個盤子直接移到C柱上

步驟3)用A柱做過渡,將B柱上n-1個盤子移到C柱上 

從這個思想來看,當將第n個盤子移動C柱上,編號為1---n-1個盤子裡的每一個盤子都進入遞迴了兩次,步驟一和步驟三,設solve(n)表示有n個盤子時第K個盤子總共移動的次數,顯然每一次移動第n個盤子下面的盤子時,第n個盤子都要進入遞迴二次,當移動第K(所求)個盤子時此時進入遞迴一次,因為最大的n-k個盤子都以移動到c柱,編號1--k個盤子再移動時,這些盤子不需要移動,所以solve(n)=2*solve(n-1),當n==k時遞迴結束,return1

遞迴的步驟就是這些,想明白了你就會發現,第k個盤子一共的總次數也就是2的n-k次方

AC程式碼一遞迴:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int k;
ll solve(int n)
{
	if(n==k)
		return 1;
	else
		return 2LL*solve(n-1);
}
int main()
{
	int t,n;
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		cout<<solve(n)<<endl;
	}
	return 0;
}

AC程式碼二:快速冪求解2的n-k次方

#include<iostream>
using namespace std;
typedef long long ll;
ll pow(ll m,ll n)//快速冪m的n次方 
{
	ll ans=1;
	while(n)
	{
		if(n&1)
			ans=ans*m;
		m=m*m;
		n>>=1;
	}
	return ans;
}
int main()
{
	ll T,k,n;
	cin>>T;
	while(T--)
	{
		cin>>n>>k;
		cout<<pow(2ll,n-k)<<endl;
	}
	return 0;
}