标签:经典 copy class mil 大小 break space %s cdn
汉诺塔由三根柱子(分别用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次方。
3
AB BC CA BA CB AC
7
2
AB BA CA BC CB AC
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 }
标签:经典 copy class mil 大小 break space %s cdn
原文地址:https://www.cnblogs.com/five20/p/9037470.html