BZOJ 1019: [SHOI2008]汉诺塔

传送门

回忆一下经典的汉诺塔的递推公式:

$f[i]=2f[i-1]+1$,然后回忆一下过程

发现经典汉诺塔的操作也是可以有优先级的

所以考虑可能其他优先级也同样可以递推

具体证明可以参照经典汉诺塔

那么设 $f[i]=kf[i-1]+b$,考虑如何求 k,b

暴力模拟n=1,2,3的情况,求出 f[1,2,3] 后代入就可以求出 k,b 了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
int n,k,b;
ll f[107];
int p[7][2];//优先级
int m,now[4][4],Top[4];//now模拟3个柱子,Top是盘子叠的数量
void dfs(int fa,int stp)//爆搜
{
    if(Top[3]==m||Top[2]==m) { f[m]=stp; return; }//到达结束状态就记录f
    for(int i=1;i<=6;i++)//按优先级枚举
    {
        int a=p[i][0],b=p[i][1];
        if(a==fa||(!Top[a])) continue;//如果上一步走过了或者当前柱子没有盘子就不考虑
        if(now[a][Top[a]]>now[b][Top[b]]&&Top[b]) continue;//判断另一个位置能不能放
        Top[b]++; now[b][Top[b]]=now[a][Top[a]];//模拟放盘子
        now[a][Top[a]]=0; Top[a]--;
        dfs(p[i][1],stp+1); break;//只要找一种方案
    }
}
int main()
{
    n=read(); char s[10];
    for(int i=1;i<=6;i++)
        scanf("%s",s),p[i][0]=s[0]-'A'+1,p[i][1]=s[1]-'A'+1;
    for(m=1;m<=3;m++)
    {
        memset(now,0,sizeof(now));
        memset(Top,0,sizeof(Top)); Top[1]=m;
        for(int i=1;i<=m;i++) now[1][i]=m-i+1;
        dfs(0,0);
    }
    k=(f[3]-f[2])/(f[2]-f[1]); b=f[3]-f[2]*k;
    for(int i=4;i<=n;i++) f[i]=f[i-1]*k+b;
    cout<<f[n];
    return 0;
}

 

 

posted @ 2018-12-18 17:16  LLTYYC  阅读(148)  评论(0编辑  收藏  举报