bzoj1019: [SHOI2008]汉诺塔(动态规划)

1019: [SHOI2008]汉诺塔

题目:传送门

简要题意:

   和经典的汉诺塔问题区别不大,但是题目规定了一个移动时的优先级:

   如果当前要从A柱子移动,但是A到C的优先级比A到B的优先级大的话,那就只能从A移到C


题解:

   首先我们回顾一下基础的汉诺塔问题:

   要达到最少步数,那就先把A柱子上除最后一个盘子外,全都移到B,然后将A的最后一个盘子移到C,再把B的移到C就ok 复杂度就是2^n-1

  

   但是这题稍微有点恶心,规定了一个优先级,那么我们可以分情况来讨论:

   定义:f[5][50];//第i个柱子移动j个盘子到优先级最高柱子的最优解    p[5][50];//第i个柱子移动j个盘子到p[i][j]是最高优先级

   这样子我们肯定是希望 f[a][i]=f[a][i-1]+1+f[b][i-1];(也就是最基础的情况,正如上面所述,当然是我们的理想状态之中的啦)

   但是再去考虑优先级,就会出现另外的情况:

   如果我把A上的i-1个都移到了B,且将第i个移到了C,这时候我们需要再次移动B上的(按照基础的操作)

   但是因为优先级的限制,我们不一定再移动B时可以移到C,万一移到A的优先级更高呢?

   如果移到C就不说了(就是理想的)

   如果到A,那么几番辗转之后最终就不是到C了,而是会全部移到B

   则:f[a][i]=f[a][i-1]+1+f[b][i-1]+1+f[a][i-1]-->f[a][i-1]*2+2+f[b][i-1];


代码:

 #include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int n,st[],ed[];
LL f[][];//第i个柱子移动j个盘子到优先级最高柱子的最优解
int p[][];//第i个柱子移动j个盘子到p[i][j]是最高优先级
// f[a][i]=f[a][i-1]+1+f[b][i-1];
// f[a][i-1]*2+2+f[b][i-1];
int main()
{
scanf("%d",&n);
char s[];
for(int i=;i<=;i++)
{
scanf("%s",s);
st[i]=s[]-'A'+;ed[i]=s[]-'A'+;
}
for(int i=;i<=;i++)f[i][]=1LL;
for(int i=;i>=;i--)p[st[i]][]=ed[i];//倒着处理,对于优先级低的会被覆盖,所以就不存
for(int i=;i<=n;i++)
{
for(int a=;a<=;a++)
{
int b=p[a][i-],c=-a-b;//如解析中的b,c
if(p[b][i-]==c){f[a][i]=f[a][i-]++f[b][i-];p[a][i]=c;}
else {f[a][i]=f[a][i-]*++f[b][i-];p[a][i]=b;}
}
}
printf("%lld\n",f[][n]);
return ;
}
上一篇:前端基础:HTML标签(上)


下一篇:input file控件限制上传文件类型