1. 程式人生 > >P4285 [SHOI2008]漢諾塔

P4285 [SHOI2008]漢諾塔

圖片 using 由於 out lin 例如 之前 str 超過

題目描述

漢諾塔由三根柱子(分別用A、B、C表示)和n個大小互不相同的空心盤子組成。一開始n個盤子都摞在柱子A上,大的在下面,小的在上面,形成了一個塔狀的錐形體。 對漢諾塔的一次合法的操作是指:從一根柱子的最上層拿一個盤子放到另一根柱子的最上層,同時要保證被移動的盤子一定放在比它更大的盤子上面(如果移動到空柱子上就不需要滿足這個要求)。我們可以用兩個字母來描述一次操作:第一個字母代表起始柱子,第二個字母代表目標柱子。例如,AB就是把柱子A最上面的那個盤子移到柱子B。漢諾塔的遊戲目標是將所有的盤子從柱子A移動到柱子B或柱子C上面。 有一種非常簡潔而經典的策略可以幫助我們完成這個遊戲。首先,在任何操作執行之前,我們以任意的次序為六種操作(AB、AC、BA、BC、CA和CB)賦予不同的優先級,然後,我們總是選擇符合以下兩個條件的操作來移動盤子,直到所有的盤子都從柱子A移動到另一根柱子: (1)這種操作是所有合法操作中優先級最高的; (2)這種操作所要移動的盤子不是上一次操作所移動的那個盤子。 可以證明,上述策略一定能完成漢諾塔遊戲。現在你的任務就是假設給定了每種操作的優先級,計算按照上述策略操作漢諾塔移動所需要的步驟數。

技術分享圖片

輸入輸出格式

輸入格式:

輸入有兩行。第一行為一個整數n(1≤n≤30),代表盤子的個數。第二行是一串大寫的ABC字符,代表六種操作的優先級,靠前的操作具有較高的優先級。每種操作都由一個空格隔開。

輸出格式:

只需輸出一個數,這個數表示移動的次數。我們保證答案不會超過10的18次方。

輸入輸出樣例

輸入樣例#1:
3
AB BC CA BA CB AC
輸出樣例#1:
7
輸入樣例#2:
2
AB BA CA BC CB AC
輸出樣例#2:
5

說明

對於20%的數據,n ≤ 10。 對於100%的數據,n ≤ 30。

Solution:

  本題由於題面中說道按照上述方法一定能有答案。

  那麽我們由普通的$hanoi$三塔的遞推式:$d[i]=2*d[i-1]+1$(現實意義是將$i-1$個移動到$B$柱,再將$A$柱的一個移動到$C$柱,最後把$B$柱的$i-1$個移動到$C$柱),具體證明直接數歸,還是比較簡單的。

  然後擴展到本題,我們可以直接$dfs$處理出$n=1,2,3$的情況所對應的$d[1],d[2],d[3]$。

  由數歸不難得出:$d[i]=k*d[i-1]+b$(可以類比普通$hanoi$塔)。

  則$k=\frac{d[3]-d[2]}{d[2]-d[1]},\;b=d[3]-d[2]*k$。

  最後$O(n)$遞推即可得到$d[n]$了。

代碼:

 1 #include<bits/stdc++.h>
 2 #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
 3 #define il inline
 4 #define ll long long
 5 using namespace std;
 6 const int N=35;
 7 int n;
 8 ll d[N];
 9 int stk[5][5],cnt[4];
10 struct node{
11     int fr,to;
12 }a[N];
13 bool vis[4];
14 char s[4];
15 il void dfs(int p,int c,int lst){
16     if(cnt[1]==c||cnt[2]==c){d[c]=p;return;}
17     For(i,1,6){
18         int j=a[i].fr,k=a[i].to;
19         if(cnt[j]&&j!=lst){
20             if(stk[j][cnt[j]]<stk[k][cnt[k]]||!stk[k][cnt[k]]){
21                 stk[k][++cnt[k]]=stk[j][cnt[j]];
22                 cnt[j]--;
23                 dfs(p+1,c,k);
24                 break;
25             }
26         }
27     }
28 }
29 int main(){
30     scanf("%d",&n);
31     For(i,1,6){
32         scanf("%s",s);
33         a[i].fr=s[0]-A,a[i].to=s[1]-A;
34     }
35     stk[0][++cnt[0]]=1;
36     dfs(0,1,-1);
37     cnt[1]=cnt[2]=cnt[0]=0;
38     For(i,1,2)stk[0][++cnt[0]]=3-i;
39     dfs(0,2,-1);
40     cnt[1]=cnt[2]=cnt[0]=0;
41     For(i,1,3)stk[0][++cnt[0]]=4-i;
42     dfs(0,3,-1);
43     if(n<=3)cout<<d[n];
44     else {
45         ll k=(d[3]-d[2])/(d[2]-d[1]),q=d[3]-k*d[2];
46         For(i,4,n)d[i]=1ll*k*(d[i-1])+q;
47         cout<<d[n];
48     }
49     return 0;
50 }

P4285 [SHOI2008]漢諾塔