zoukankan      html  css  js  c++  java
  • P4285 [SHOI2008]汉诺塔

    题目描述

    汉诺塔由三根柱子(分别用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]$了。

    代码:

    #include<bits/stdc++.h>
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define il inline
    #define ll long long
    using namespace std;
    const int N=35;
    int n;
    ll d[N];
    int stk[5][5],cnt[4];
    struct node{
        int fr,to;
    }a[N];
    bool vis[4];
    char s[4];
    il void dfs(int p,int c,int lst){
        if(cnt[1]==c||cnt[2]==c){d[c]=p;return;}
        For(i,1,6){
            int j=a[i].fr,k=a[i].to;
            if(cnt[j]&&j!=lst){
                if(stk[j][cnt[j]]<stk[k][cnt[k]]||!stk[k][cnt[k]]){
                    stk[k][++cnt[k]]=stk[j][cnt[j]];
                    cnt[j]--;
                    dfs(p+1,c,k);
                    break;
                }
            }
        }
    }
    int main(){
        scanf("%d",&n);
        For(i,1,6){
            scanf("%s",s);
            a[i].fr=s[0]-'A',a[i].to=s[1]-'A';
        }
        stk[0][++cnt[0]]=1;
        dfs(0,1,-1);
        cnt[1]=cnt[2]=cnt[0]=0;
        For(i,1,2)stk[0][++cnt[0]]=3-i;
        dfs(0,2,-1);
        cnt[1]=cnt[2]=cnt[0]=0;
        For(i,1,3)stk[0][++cnt[0]]=4-i;
        dfs(0,3,-1);
        if(n<=3)cout<<d[n];
        else {
            ll k=(d[3]-d[2])/(d[2]-d[1]),q=d[3]-k*d[2];
            For(i,4,n)d[i]=1ll*k*(d[i-1])+q;
            cout<<d[n];
        }
        return 0;
    }
  • 相关阅读:
    程序员下班去超市购物与收银员的一段搞笑对白 续集
    2010年9月02日周四_Deploying ArcGIS Mobile applications_4.1
    2010年8月30日周一_Adding layers _7.2
    2010年8月30日周一_Creating A Map_7.1
    2010年9月01日周三_CreatingAndPublishingaMobileWebService_3.2
    2010年8月29日周日_Deployment_6
    2010年8月31日周二_Navigating the map_7.3
    2010年8月30日周一_Introduction to ArcGIS Mobile SDK_1
    2010年9月01日周三_Using GPS data and devices_3.3
    2010年8月29日周日_Using the Sample Xcode Projects_5
  • 原文地址:https://www.cnblogs.com/five20/p/9037470.html
Copyright © 2011-2022 走看看