zoukankan      html  css  js  c++  java
  • codevs 1255 搭积木 x

    1255 搭积木

     时间限制: 1 s

     空间限制: 128000 KB

     题目等级 : 大师 Master

    题目描述 Description

    一种积木搭建方式,高为H的积木,最底层有M个积木,每一层的积木数是他的低一层的积木数+1-1。总共有N个积木。(且每行积木数不超过10

     

    比如下图N=13 H=6 M=2

     

    输入描述 Input Description

    第一行为三个整数、NHM

    第二行以后每行一个整数K-1为结束符。

    输出描述 Output Description

    第一行为满足NHM的积木搭建方案总数(1<=N<=540 H<=60 M<=10

    以后每一行对于对应的K,给出顺序排列的第K种方案(最小的排列为第一种)。

    (如样例中,2 1 2 3 2 3是一种方案,代表一层的积木分别为212323232321也是一种方案,212323232321要小,每个状态之间是可比的,第一个数小的排前面,第一个数相等的就看第二个数。那么所有方案就有一个顺序了,这里的K就是求第K个按顺序排列的方案)

    样例输入 Sample Input

    13 6 2

    1

    3

     -1

    样例输出 Sample Output

    3

    2 1 2 3 2 3

    2 3 2 3 2 1

    思路:

      其实有两种思路,一种是DP,另一种就是记忆化搜索.

    坑点:

      在记忆化搜索时,剪枝是必不可少的!最优剪枝应该是当 n/h>10 或者是 n/h<1 时,是绝对不可能的!搜索速度大大提高!

    代码:

    这里暂时先给出记忆化搜索的代码~

    /*
    作者:狐白酒(my name on the codevs!)
    题目:p1255 搭积木
    */
    
    #include <iostream>
    #include <cstdio>
    #define LL long long
    
    using namespace std;
    
    int N,H,M;
    bool v[62][542][12];
    LL f[62][542][12];
    
    LL dfs(int h,int n,int m)///high,sum,down
    {
        if(n/h>10 || n/h<1) return f[h][n][m]=0;
    ///这里剪枝剪的特多~
        if(v[h][n][m]) return f[h][n][m];
        else
        {
            if(h==1)
            {
                v[h][n][m]=1;
                if(n==m && m<=10)
                    return f[h][n][m]=1;
                else 
                    return f[h][n][m]=0;
            }
            if(h>=2)
            {
                LL s=0;
                if(m-1>=1)
                    s+=dfs(h-1,n-m,m-1);
                if(m+1<=10)
                    s+=dfs(h-1,n-m,m+1);
                v[h][n][m]=1;
                return f[h][n][m]=s;
            }
        }
    }
    
    void ask(LL x,int h,int n,int m)
    {
        printf("%d ",m);
        if(h>=2)
        {
            if(x<=f[h-1][n-m][m-1])
                ask(x,h-1,n-m,m-1);
            else 
                ask(x-f[h-1][n-m][m-1],h-1,n-m,m+1);
        }
    }
    
    int main()
    {
        scanf("%d%d%d",&N,&H,&M);
        dfs(H,N,M);
        cout<<f[H][N][M]<<endl;
        LL k;
        while(cin>>k)
        {
            if(k==-1) break;
            ask(k,H,N,M);
            printf("
    ");
        }
        return 0;
    }
    View Code

    过几天再把动规的补上~

     

    End.

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    C#跨平台开源项目实战(WPF/Android/IOS/Blazor)
    WPF应用程序关闭模式(ShutdownMode)
    git修改提交记录的用户信息
    WPF摄像头使用(AForge)
    VisualStudio AppCenter 应用介绍
    EntityFrameworkCore 工具命令行总结
    FILEtoJPG-神秘文件 -更新(软件BUG及建议可以在这里反馈)
    开启网赚新方法:微信小号挂机-每天赚个早饭钱
    Android 7.0 以上保留数据去除锁屏密码的方法
    使用 GitHub+Hexo 搭建个人博客
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/7082523.html
Copyright © 2011-2022 走看看