• POJ1037 A decorative fence 动态规划思想解组合数


    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    using namespace std;
    
    /*
    该题给定一个N,那么在有1.2.3...N个数字的情况下,这些数字高低交替进行排列
    把所有符合情况的进行一个字典序排列,问第C个排列是一个怎样的排列
    up[i][j]代表长度为i,第一位为j且后面需跟着一个上升数字的方案总数
    dn[i][j]代表长度为i,第一位为j且后面需跟着一个下降数字的方案总数
    根据我们所定义的状态,我们能够得到一个状态的转移关系(用来状态转移来求解方案数)
    up[i][j] = SUM{ dn[i-1][k] 且 k >= j } 
    dn[i][j] = SUM( up[i-1][k] 且 k < j )
    */
    typedef long long int64;
    
    int N, path[25], idx;
    int64 C, up[25][25], dn[25][25];
    
    void prep() {
        up[1][1] = dn[1][1] = 1;
        for (int i = 2; i <= 20; ++i) {
            for (int j = 1; j <= i; ++j) { // 枚举长度为i第一位为j
                for (int k = 1; k < j; ++k) {
                    dn[i][j] += up[i-1][k];
                }
                for (int k = j; k < i; ++k) { // 这个地推需要将后面的数字进行一个映射 
                // 例如 1,2,3,4,5 假设j=3, 那么还剩下1,2,4,5 比3大的数就只有4,5 那么
                // 这两个数就可以看做长度为4的情况下的3,4.也就有了[j,i-1]来枚举这个k了
                    up[i][j] += dn[i-1][k];
                }
            }
        }
    }
    
    void dfs(int64 x, int bound, int num, int r) {
        if (r > 0) { // 要求后面要跟一个上升的数字
            for (int i = num; i <= bound; ++i) {
                if (x - dn[bound][i] <= 0) {
                    path[++idx] = i;
                    dfs(x, bound-1, i, -1);
                    break;
                } else {
                    x -= dn[bound][i];
                }
            }
        }
        else { // 要求后面跟一个下降的数字
            for (int i = 1; i < num; ++i) {
                if (x - up[bound][i] <= 0) {
                    path[++idx] = i; 
                    dfs(x, bound-1, i, 1);
                    break;
                } else {
                    x -= up[bound][i];
                }
            }
        }
    }
    
    void deal(int64 x, int bound) {
        for (int i = 1; i <= bound; ++i) {
            if (x - dn[bound][i] <= 0) { // 小于等于0说明在这个数字开始的区域内
                path[++idx] = i;
                dfs(x, bound-1, i, -1); // +1或-1表示下一个数字的大小关系
                break;
            } else {
                x -= dn[bound][i]; // 先减去以i开始下降的部分
            }
            if (x - up[bound][i] <= 0) {
                path[++idx] = i;
                dfs(x, bound-1, i, 1);
                break;
            } else {
                x -= up[bound][i]; // 再减去以i开始上升的部分
            }
        }
    }
    
    int main() {
        prep();  // 一个预处理来求出某些常量的组合数 
        int T;
        scanf("%d", &T);
        while (T--) {
            bool vis[25] = {false};
            idx = 0;
            scanf("%d %I64d", &N, &C);
            deal(C, N);
            printf("%d", path[1]);
            vis[path[1]] = true;
            for (int i = 2; i <= idx; ++i) {
                int cnt = 0;
                for (int j = 1; j <= N; ++j) {
                    if (!vis[j]) ++cnt;
                    if (cnt == path[i]) {
                        printf(" %d", j);
                        vis[j] = true;
                        break;
                    }
                } 
            }
            puts("");
        }    
        return 0;
    } 
  • 相关阅读:
    UWP 常用文件夹
    UWP 判断Windows10系统版本
    UWP 图片缩放
    Windows 10「设置」应用完整MS-Settings快捷方式汇总
    UWP 用Thumb 控件仿制一个可拖动悬浮 Button
    【mp3】洗脑循环了!龙珠超 自在极意功 【究极の圣戦】串田アキラ 背景纯音乐
    工作三年后的总结
    css3 移动端 开关效果
    js 移动端上拉加载下一页通用方案
    【我的上传番剧/电影】收藏夹
  • 原文地址:https://www.cnblogs.com/Lyush/p/2854773.html
Copyright © 2020-2023  润新知