BZOJ1019: [SHOI2008]汉诺塔

来源:互联网 发布:导出数据库命令 编辑:程序博客网 时间:2024/05/21 18:49

这题有一个挺厉害的DP解法

一共有三根柱子,编号a,b,c
考虑一开始n个盘子堆在第a个柱子上,
他们全部移到另一柱子的充要条件时第n个盘子即最下的盘子移动
第n个盘子移动的充要条件是他上面的n-1个盘子全部移到另一柱子b,那么根据题目的约束,这时候只能移动第n个盘子到剩下的空柱子c上
移动后,根据约束,只能移动那n-1个盘子
有2种情况:
1:n-1个盘子移到c上,结束操作
2:n-1个盘子移到a上,继续上文的操作
保证有解就不用判死循环了

所以,计算f[i][j],g[i][j]表示i个盘子,在第j个柱子上,全部移到另一个柱子需要步数,会移到哪个柱子,转移的话按照上文讨论一下就好了

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;inline void swap(int &x,int &y){x^=y;y^=x;x^=y;}inline int read(){    char c; int x;    while(!((c=getchar())>='0'&&c<='9'));    x=c-'0';    while((c=getchar())>='0'&&c<='9') (x*=10)+=c-'0';    return x;}const int maxn = 40;char str[10];int dx[7],dy[7];ll f[maxn][4]; int g[maxn][4];int n;int main(){    n=read();    for(int i=1;i<=6;i++)    {        scanf("%s",str);        if(str[0]=='A') dx[i]=1;        if(str[0]=='B') dx[i]=2;        if(str[0]=='C') dx[i]=3;        if(str[1]=='A') dy[i]=1;        if(str[1]=='B') dy[i]=2;        if(str[1]=='C') dy[i]=3;    }    for(int i=1;i<=3;i++)        for(int j=1;j<=6;j++)if(dx[j]==i)        {            f[1][i]=1ll; g[1][i]=dy[j]; break;        }    for(int i=2;i<=n;i++)        for(int j=1;j<=3;j++)        {            int t1=g[i-1][j]; f[i][j]=f[i-1][j];            int t2; for(t2=1;t2<=3;t2++) if(t2!=j&&t2!=t1) break;            f[i][j]++;            f[i][j]+=f[i-1][t1]; t1=g[i-1][t1]; g[i][j]=t1;            while(t1!=t2)            {                for(int k=1;k<=3;k++) if(k!=t1&&k!=t2) {t2=k;break;}                f[i][j]++;                f[i][j]+=f[i-1][t1]; t1=g[i-1][t1];                g[i][j]=t1;            }        }    printf("%lld\n",f[n][1]);    return 0;}
0 0
原创粉丝点击