• [NOIp2015]斗地主


    Description

    Luogu2688
    给定一手牌,问最少几步把这手牌打完。

    Solution

    DP出散牌,暴力找顺子。

    由于顺子可能会出现多余的单牌,所以暴力的枚举如何出顺子才更优。

    DP就是一个暴力DP,没有什么有趣的地方,不过不要忘了拆牌。

    Code

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using std::min;
    
    const int N = 25;
    
    int f[N][N][N][N][3];
    int mx[N];
    int a[N];
    int my[N];
    int ans = 1000, n;
    
    void init() {
        f[0][0][0][0][0] = 0;
        for (int r = 0; r <= mx[5]; ++r) {
            for (int l = 0; l <= mx[4]; ++l) {
                for (int k = 0; k <= mx[3]; ++k) {
                    for (int j = 0; j <= mx[2]; ++j) {
                        for (int i = 0; i <= mx[1]; ++i) {
                            int x = 1000;
                            // 出散牌:
                            if (i) x = min(x, f[i-1][j][k][l][r]);
                            if (j) x = min(x, f[i][j-1][k][l][r]);
                            if (k) x = min(x, f[i][j][k-1][l][r]);
                            if (l) x = min(x, f[i][j][k][l-1][r]);
                            if (r) x = min(x, f[i][j][k][l][r-1]);
                            if (r>1) x = min(x, f[i][j][k][l][r-2]);
                            // 三带/拆三
                            if (k) {
                                if (i) x = min(x, f[i-1][j][k-1][l][r]);
                                if (j) x = min(x, f[i][j-1][k-1][l][r]);
                                if (r) x = min(x, f[i][j][k-1][l][r-1]);
                                if (r>1) x = min(x, f[i][j][k-1][l][r-2]);
                                x = min(x, f[i+1][j+1][k-1][l][r] - 1);
                            }
                            // 四带/拆四
                            if (l) {
                                if (i>1) x = min(x, f[i-2][j][k][l-1][r]);
                                if (i && r) x = min(x, f[i-1][j][k][l-1][r-1]);
                                if (r>1) x = min(x, f[i][j][k][l-1][r-2]);
                                if (j>1) x = min(x, f[i][j-2][k][l-1][r]);
                                if (j && r>1) x = min(x, f[i][j-1][k][l-1][r-2]);
                                if (j) x = min(x, f[i][j-1][k][l-1][r]);
                                if (l>1) x = min(x, f[i][j][k][l-2][r]);
                                x = min(x, f[i+1][j][k+1][l-1][r] - 1);
                            }
                            f[i][j][k][l][r] = min(x + 1, f[i][j][k][l][r]);
                        }
                    }
                }
            }
        }
    }
    
    void dfs(int x) {
        if (x > ans) return;
        for (int k = 1, flag; k <= 3; ++k) {
            for (int i = 1; i <= 12; ++i) {
                flag = 1;
                int len = 4 / k + 1;
                while (flag && i + len - 1 <= 12) {
                    for (int j = 1; j <= len; ++j) {
                        if (a[i+j-1] < k) {
                            flag = 0;
                            break;
                        }
                    }
                    if (!flag) break;
                    for (int j = 1; j <= len; ++j) {
                        a[i+j-1] -= k;
                    }
                    dfs(x+1);
                    for (int j = 1; j <= len; ++j) {
                        a[i+j-1] += k;
                    }
                    len++;
                }
            }
        }
        memset(my, 0, sizeof my);
        for (int i = 1; i <= 13; ++i) my[a[i]]++;
        my[5] = a[14];
        ans = min(ans, x + f[my[1]][my[2]][my[3]][my[4]][my[5]]);
    }
    
    int main() {
        memset(f, 0x3f, sizeof f);
        int t;
        scanf("%d%d
    ", &t, &n);
        mx[1] = n; mx[2] = n / 2; mx[3] = n / 3; mx[4] = n / 4; mx[5] = 2;
        init();
        while (t--) {
            ans = 1000;
            memset(a, 0, sizeof a);
            for (int i = 1, x, y; i <= n; ++i) {
                scanf("%d%d", &x, &y);
                if (x == 0) a[14]++;
                else if (x <= 2) a[11+x]++; 
                else a[x-2]++;
            }
            dfs(0);
            printf("%d
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    图形
    附属信息
    文件操作
    字符编码
    Python数据类型之基础记。。。
    python并发编程之多进程
    python并发编程之多进程
    计算机基础之计算机系统的简单了解。
    元类
    基于socketserver模块实现并发tcp/udp
  • 原文地址:https://www.cnblogs.com/wyxwyx/p/noip201513.html
Copyright © 2020-2023  润新知