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];
代码:
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 typedef long long LL; 5 int n,st[10],ed[10]; 6 LL f[5][50];//第i个柱子移动j个盘子到优先级最高柱子的最优解 7 int p[5][50];//第i个柱子移动j个盘子到p[i][j]是最高优先级 8 // f[a][i]=f[a][i-1]+1+f[b][i-1]; 9 // f[a][i-1]*2+2+f[b][i-1]; 10 int main() 11 { 12 scanf("%d",&n); 13 char s[5]; 14 for(int i=1;i<=6;i++) 15 { 16 scanf("%s",s); 17 st[i]=s[0]-'A'+1;ed[i]=s[1]-'A'+1; 18 } 19 for(int i=1;i<=3;i++)f[i][1]=1LL; 20 for(int i=6;i>=1;i--)p[st[i]][1]=ed[i];//倒着处理,对于优先级低的会被覆盖,所以就不存 21 for(int i=2;i<=n;i++) 22 { 23 for(int a=1;a<=3;a++) 24 { 25 int b=p[a][i-1],c=6-a-b;//如解析中的b,c 26 if(p[b][i-1]==c){f[a][i]=f[a][i-1]+1+f[b][i-1];p[a][i]=c;} 27 else {f[a][i]=f[a][i-1]*2+2+f[b][i-1];p[a][i]=b;} 28 } 29 } 30 printf("%lld\n",f[1][n]); 31 return 0; 32 }