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; }