題目:https://vjudge.net/problem/UVA-10795
新漢諾塔問題往舊漢諾塔問題上轉換,所以先來看舊漢諾塔問題。
舊漢諾塔:
漢諾塔問題是一個經典的問題。漢諾塔(Hanoi Tower),又稱河內塔,源於印度一個古老傳說。 大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。
大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。
並且規定,任何時候,在小圓盤上都不能放大圓盤,且在三根柱子之間一次只能移動一個圓盤。
問應該如何操作?
既然是個遞推問題,那就從大到小的依次找圓盤,若想把第n個圓盤放到第i根柱子上,首先保證,第i根柱子上沒有比n小的盤子,
且n上面也無任何圓盤,所以這時候才能把n放到第i根柱子上。依次類推到第1個盤子。
在寫遞推函數的時候要逆着寫,不要順着往下想,比如在考慮n的情況的時候,要先想第n-1個情況已經完成了,這時候n該幹什麼了,這個函數的是爲n-1後n的情況進行的治理,所以也是分治情況的一種。
所以該這樣實現:
#include<bits/stdc++.h>
using namespace std;
void hannuo(int n,char first,char middle,char end){
if(n<1)
return ;
hannuo(n-1,first,end,middle);
printf("把%d從%c放入到了%c\n",n,first,end);
hannuo(n-1,middle,first,end);
}
int main(){
int n;
printf("有多少個盤子\n");
scanf("%d",&n);
hannuo(n,'a','b','c');
}
再來看新漢諾塔問題,由於一開始情況未知,所以要往舊漢諾塔問題上轉換,
初始局面和目標局面移動到參考局面的和加1就是結果。
參考局面:要移動的編號爲n的盤子單獨在一根柱子上,其他的棋盤全都在除了n所在和n目標柱子的柱子上。
所以f(start,n-1,other)表示初始局面到參考局面,
參考局面到目標局面是針對於第n-1個盤子來說的,因爲移動可逆,也可以想成是目標局面到參考局面,這麼想只是爲了
函數更好的實施。
所以目標局面到參考局面f(finish,n-1,other).
這個時候每個單獨的f(),就轉換成了舊漢諾塔問題,而舊漢諾塔問題中,每把n個柱子移動到另一個柱子上,需要的
步是2^i-1步。
這個問題就因此解決了
實現:
#include<bits/stdc++.h>
using namespace std;
const int maxn=65;
typedef long long LL;
int n;
int start[maxn],finish[maxn];
long long f(int *p,int i,int final){
if(i==0) return 0;
if(p[i]==final) return f(p,i-1,final);
return f(p,i-1,6-p[i]-final)+(1LL<<(i-1));
}
int main(){
int kase=0;
while(scanf("%d",&n) && n){
for(int i=1;i<=n;i++) scanf("%d",&start[i]);
for(int i=1;i<=n;i++) scanf("%d",&finish[i]);
int k=n;
while(k>=1 && start[k]==finish[k]) k--;
long long ans=0;
if(k>=1){
int other=6-start[k]-finish[k];
ans=f(start,k-1,other)+f(finish,k-1,other)+1;
}
printf("Case %d: %lld\n",++kase,ans);
}
return 0;
}