1. 程式人生 > >解決 漢諾塔 2,3,4

解決 漢諾塔 2,3,4

參考HDU2064和2077

漢諾塔2:a,b,c三柱,n個圓盤,大的不能放在小的上面,每次移動一個 漢諾塔3:a,b,c三柱,n個圓盤,大的不能放在小的上面,每次移動一個,且只能在相鄰柱子之間移動 漢諾塔4:a,b,c三柱,n個圓盤,大的不能放在小的上面,每次移動一個,且只能在相鄰柱子之間移動;(加上一個特例:只有最大的圓盤可以放在小的上面,即第n個圓盤

一個一個解決: 宣告: 1.文中x1->x2表示從x1移動一個圓盤到x2 2.函式名mx(int n,a,b,c)表示從a移動n個圓盤經過b到c 漢諾塔2: 當n==1;a柱只有一個圓盤,直接a->c 當n>1;先將a柱的n-1個圓盤移動到b,然後a->c,將剩下的n-1個圓盤從b移動到c;

m1(int n,a,b,c){ if(n==1) a->c; else{ m1(n-1,a,c,b); a->c; m1(n-1,b,a,c); } } 可以得出 1.m(1)=1 2.m(n)=m(n-1)*2+1; 然後不論使用函式遞迴還是陣列遞迴都可以解決問題,不過要提醒,在刷題是用函式遞迴因為時間超出是不能提交成功的。下面兩種情況也是如此,我會在漢諾塔4中詳細說明兩種程式碼,前兩種不予解決問題程式碼

漢諾塔3: 1.當n==1時,直接a到b到c 2.當n>1時,先把n-1個圓盤由a移動到c,在把第n個圓盤從a移動到b,在把n-1個圓盤從c移動到a,在把第n個圓盤從b移動到c

m1(int n,a,b,c){ if(n==1)a->b->c; else{ m1(n-1,a,b,c); a->b; m1(n-1,c,b,a); b->c; m1(n-1,a,b,c); } }

由此可以得到 1.m1(1)=1 2.m1(n)=m1(n-1)*3+2;

漢諾塔4(題目來源HDU2077): 這個問題網上的答案我只能說我看不懂,看的懂就不會費這些時間研究了!

先給出我最開始的想法:

函式m(int n,a,b,c)(附:解決漢諾塔4問題) 當n==1; 直接a->b->c; 當n>1;先把n-1圓盤從a移動到b,在把第n個圓盤a->b->c;然後把n-1個圓盤從b移動到c

;

函式m1(int n,a,c,b) (附:解決函式m中的"把n-1個圓盤從a移動到b"

當n==1;直接b->c; 當n>1;先把n-1個圓盤從a移動到c;再把第 n個圓盤從a移動到b;再把n-1個圓盤從c移動到b m1(int n,a,c,b) {

if(n==1)a->b; else{ m3(n-1,a,b,c); a->b; m1(n,c,a,b); }

函式m2(int n,b,a,c)(附:解決函式m中“把n-1個圓盤從b移動到c” 當n==1;直接直接b->c 當n>1:先把n-1個圓盤從b移動到a;再把第n個圓盤從b移動到c;再把n-1個圓盤從a移動到c

m2(int n,b,a,c){ if(n==1)b->c; else{ m2(n-1,b,c,a) b->c; m3(n-1,a,b,c); }

函式m3(int n,a,b,c)(附:解決m1中“先把n-1個圓盤從a移動到c”和m2中的“再把n-1個圓盤從a移動到c” 當n==1;直接a->b->c 當n>1;先將n-1個圓盤從a移動到c;再把第n個圓盤從a移動到b;再把n-1個圓盤從c移動到a;再把第n個圓盤從b移動到c;再把n-1個圓盤從a移動到c

m3(int n,a,b,c) { if(n==1) a->b->c; else{ m3(n-1,a,b,c); a->b; m3(n-1,c,b,a); b->c; m3(n-1,a,b,c); }

下面附上我遞迴函式的程式碼:

#include <stdio.h> int c; void m1(int n); void m3(int n); void m(int n){

if(n==1)c+=2;
else{
	m1(n-1);
	c+=2;
	m1(n-1);
}

}

void m1(int n){

if(n==1)c+=1;
else{
	m3(n-1);
	c+=1;
	m1(n-1); 
}

}

void m3(int n){

if(n==1)c+=2;
else{
	m3(n-1);
	c+=1;
	m3(n-1);
	c+=1;
	m3(n-1); 
}

} int main(){

int n,l;
scanf("%d",&n);
while(n--){
	c=0;
	scanf("%d",&l);
	m(l);
	printf("%d\n",c);
}

}

全域性int用來記住總共移動次數,可以解決問題,但時間超了,提交失敗

上面的幾個函式可以總結為 m(n)=m1(n-1)+m2(n-1)+2; m1(n)=m3(n-1)+m1(n-1)+1; m2(n)=m2(n-1)+m3(n-1)+1; m3(n)=m3(n-1)*3+2;

發現m1和m2函式似乎作用一樣,把m2全部改為m1 m(n)=m1(n-1)*2+2; m1(n)=m1(n-1)+m3(n-1)+1; m3(n)=m3(n-1)*3+2;

這裡動用陣列解決: 題目裡面的n最大為20,所以我先算出m1陣列和m3陣列的前20專案;最後簡單呼叫, 提交成功

#include <stdio.h>

int main(){

int n,num;
scanf("%d",&n);
long long m,m1[20],m3[20];
m3[0]=2;m1[0]=1;
for(int i=1;i<20;i++){
	
	m3[i] = m3[i-1]*3+2;
	m1[i] = m1[i-1]+m3[i-1]+1;
}
while(n--){
	scanf("%d",&num);
	m =(num==0)?0:((num==1)?2:2*m1[num-2]+2);
	printf("%lld\n",m);
}

} (全程碼字,無功有苦,見諒)