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