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 }

 

posted @ 2018-03-10 08:48  CHerish_OI  阅读(101)  评论(0编辑  收藏