• zoj 2338


    HanioTower的加强版


    记f[n][m]为n个disc,m个peg的Hanoi问题,则有dp公式f[n][m]=min{f[n-k][m-1]+2*f[k][m]}。即把上面的k个disc利用m个peg转移某个中间peg,再把下面的n-k个disc利用m-1个peg转移到目标peg,最后把上面的k个disc利用m个peg移到目标peg。dp过程记下使得f[n][m]最小的g[n][m]=k用于反向打印移动过程。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include <stack>
    using namespace std;
    typedef unsigned long long ll;
    const ll INF=(~(0ULL))>>1;
    ll dp[70][70];
    int pre[70][70];
    stack<int>v[80];
    int n,m;
    bool was[80];
    
    void move(int from,int to) //从a这根柱子移到b这跟柱子
    {
        if(v[to].empty()) printf("move %d from %d to %d\n",v[from].top(),from,to);
        else printf("move %d from %d to %d atop %d\n",v[from].top(),from,to,v[to].top());
        v[to].push(v[from].top());
        v[from].pop();
        return ;
    }
    
    void dfs(int ct,int from,int to,int h) //ct 表示盘子个数 a,b表示柱子标号 通过h根的柱子来进行操作
    {
        int i,j,k;
        if(ct==1)
        {
            move(from,to);
            return ;
        }
        for(i=1;i<=m;i++)
            if(i!=from && i!=to && was[i]==0)break;
        dfs(pre[ct][h],from,i,h);
        was[i]=1;
        dfs(ct-pre[ct][h],from,to,h-1);
        was[i]=0;
        dfs(pre[ct][h],i,to,h);
    }
    void init(){
        int i,j,k;
        for(i=1;i<=70;i++) dp[i][3]=2*dp[i-1][3]+1,pre[i][3]=i-1;
        for(i=4;i<=65;i++){   //柱子
            dp[1][i]=1;
            for(j=2;j<=64;j++){  //盘子
                ll tem=INF;
                for(k=1;k<j;k++){ //先移走k个盘子到一个中间柱子,剩下j-k盘子移动到目标;
                    if(tem > dp[j-k][i-1]+dp[k][i]*2){
                        tem=dp[j-k][i-1]+dp[k][i]*2;
                        pre[j][i]=k;
                    }
                }
                dp[j][i]=tem;
            }
        }
    }
    int main()
    {
        int i,j,k,ca,kk;
    
        init();
        scanf("%d",&ca);
        while(ca--)
        {
            scanf("%d%d",&n,&m);
            printf("%lld\n",dp[n][m]);
            for(i=1;i<=m;i++)while(!v[i].empty())v[i].pop();
            for(i=n;i>=1;i--) v[1].push(i);
            memset(was,0,sizeof(was));
            dfs(n,1,m,m);
        }
        return 0;
    }
    


    记f[n][m]为n个disc,m个peg的Hanoi问题,则有dp公式f[n][m]=min{f[n-k][m-1]+2*f[k][m]}。即把上面的k个disc利用m个peg转移某个中间peg,再把下面的n-k个disc利用m-1个peg转移到目标peg,最后把上面的k个disc利用m个peg移到目标peg。dp过程记下使得f[n][m]最小的g[n][m]=k用于反向打印移动过程。
  • 相关阅读:
    Javescript基础api实现原理
    React Fiber
    ASP.NET中Form验证登录后反复跳转回登录页面的问题
    跨域部署Silverlight时需要注意的问题
    Windows 8 x64+Ruby 2上安装Sqlite3方法
    .NET 项目在源码控制中程序集的引用问题
    [EntLib]解决The type or namespace name 'Data' does not exist in the namespace 'Microsoft.Practices.EnterpriseLibrary' 的错误
    ASP.NET MVC Url中参数过长引发的问题
    Windows 8 x64 QQ2012/2013beta无法启动屌丝解决方法
    TechEd 2010参会小记
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/3001382.html
Copyright © 2020-2023  润新知