解決 漢諾塔 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);
}
} (全程碼字,無功有苦,見諒)