漢諾塔專題講解。

漢諾塔00

題意:三根柱子,每次移動距離無限制,一次移動一個圓盤,問將所有圓盤從AA按大小順序移動到CC最少需要多少步。

思路:因爲這裏不需要小圓盤始終在大圓盤上面,所以

設移動nn個圓盤的方案爲f(n)f(n),顯然先將n1n-1個圓盤移動到BB上需要n1n-1步。

然後最後一個圓盤移動到CC需要11步,然後再將n1n-1個圓盤移動到CC需要n1n-1步。

所以f(n)=2n1f(n)=2n-1.

漢諾塔1

題意:三根柱子,每次移動距離無限制,一次移動一個圓盤,要求小圓盤始終在大圓盤上面,問將所有圓盤從AA按大小順序移動到CC最少需要多少步。

思路:設移動nn個圓盤的方案爲f(n)f(n),顯然先將n1n-1個圓盤移動到BB上需要f(n1)f(n-1) 步,然後最後一個圓盤移動到CC需要11步,然後再將n1n-1個圓盤移動到CC需要f(n1)f(n-1)步。所以f(n)=2f(n1)+1f(n)=2n1f(n)=2f(n-1)+1\rightarrow f(n)=2^n-1 。(另外遞歸或者打表都可以找到規律)

遞歸代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
int  cnt=0;
void fun(int n,char a,char b,char c){
	 if(n==1){
	 	 printf("第%d次移動:將%d號圓盤從 %c 移動到 %c\n",++cnt,1,a,c);
	 	 return;
	 } 
	 fun(n-1,a,c,b);
	printf("第%d次移動:將%d號圓盤從 %c 移動到 %c\n",++cnt,n,a,c);
	 fun(n-1,b,a,c);
}
int main(){
	int n;
	char a='a',b='b',c='c';
	while(~scanf("%d",&n)){
		cnt=0;
		fun(n,a,b,c);
		printf("總共移動次數:%d\n",cnt);
	}
	return 0;
} 

漢諾塔2

題意:三根柱子,每次移動到相鄰柱子,一次移動一個圓盤,要求小圓盤始終在大圓盤上面,問將所有圓盤從AA按大小順序移動到CC最少需要多少步。

思路:設移動nn個圓盤的方案爲f(n)f(n),先將上面n1n-1個圓盤移動到CC上需要f(n1)f(n-1) 步,然後最後一個圓盤移動到BB需要11步,然後再將n1n-1個圓盤移動到AA需要f(n1)f(n-1)步,再將最後一個圓盤移動到CC需要一步,再將n1n-1個圓盤移動到CC需要f(n1)f(n-1)步,所以f(n)=3f(n1)+2f(n)=3n1f(n)=3f(n-1)+2\rightarrow f(n)=3^n-1

漢諾塔3

題意:四根柱子,每次移動距離無限制,一次移動一個圓盤,要求小圓盤始終在大圓盤上面,問將所有圓盤從AA按大小順序移動到DD最少需要多少步。

思路:假設以C,DC,D爲輔助柱子,從AA移動nrn-r個圓盤到BB的方案記爲f(nr)f(n-r).然後將剩下的rr個柱子利用輔助柱子CCAA移動到DD的方案爲2r12^r-1(三柱漢諾塔)。

再將nrn-r個圓盤以A,CA,C爲輔助柱子移動到DD的方案爲f(nr)f(n-r).

所以f(n)=min{2f(nr)+2r1},r[1,n]f(n)=min\{2f(n-r)+2^r-1\},r\in[1,n]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
#define mst(a) memset(a,0,sizeof a)
ll f[N];
int n; 
int main(){
	f[1]=1;
	for(int i=2;i<=64;i++){
		f[i]=1e18;
		for(int r=1;r<=i;r++){
			f[i]=min(f[i]*1.0,2*f[i-r]+pow(2,r)-1);
		}
	}
	while(~scanf("%d",&n))
	printf("%lld\n",f[n]);
	return 0;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章