zoukankan      html  css  js  c++  java
  • [Noip 2015] 斗地主

    题目描述

    牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的AAA到KKK加上大小王的共545454张牌来进行的扑克牌游戏。在斗地主中,牌的大小关 系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王3<4<5<6<7<8<9<10<J<Q<K<A<2< ext{小王}< ext{大王}3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由 nnn 张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

    现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

    需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:

    本题数据随机,不支持hack,要hack或强力数据请点击这里

    输入输出格式

    输入格式:

    第一行包含用空格隔开的2个正整数 T,nT,nT,n ,表示手牌的组数以及每组手牌的张数。

    接下来 TTT 组数据,每组数据 nnn 行,每行一个非负整数对 ai,bia_i,b_iai,bi ,表示一张牌,其中 aia_iai 表示牌的数码, bib_ibi 表示牌的花色,中间用空格隔开。特别的,我们用 111 来表示数码 AAA, 111111 表示数码J JJ, 121212 表示数码Q QQ, 131313 表示数码 KKK;黑桃、红心、梅花、方片分别用 1−41-414 来表示;小王的表示方法为 010101 ,大王的表示方法为 020202 。

    输出格式:

    TTT 行,每行一个整数,表示打光第 iii 组手牌的最少次数。

    输入输出样例

    输入样例#1: 复制
    1 8
    7 4
    8 4
    9 1
    10 4
    11 1
    5 1
    1 4
    1 1
    输出样例#1: 复制
    3
    
    输入样例#2: 复制
    1 17
    12 3
    4 3
    2 3
    5 4
    10 2
    3 3
    12 2
    0 1
    1 3
    10 1
    6 2
    12 1
    11 3
    5 2
    12 4
    2 2
    7 2
    
    输出样例#2: 复制
    6
    

    说明

    样例1说明

    共有111组手牌,包含8张牌:方片777,方片888,黑桃999,方片101010,黑桃JJJ,黑桃555,方片AAA以及黑桃AAA。可以通过打单顺子(方片777,方片888,黑桃999,方片101010,黑桃JJJ),单张牌(黑桃555)以及对子牌(黑桃AAA以及方片AAA)在333次内打光。

    对于不同的测试点, 我们约定手牌组数TTT与张数nnn的规模如下:

    数据保证:所有的手牌都是随机生成的。


    这道题真的让我感觉我的能力距noip还差远了。

    哒哒哒哒哒暴搜都不会写。

    说实话这题我看了题解,要不贪心的策略都想不出来。

    代码能力太差,写多了就调不出来。

    先爆搜顺子,根据题解的意思, 三顺子其实没必要出, 因为不如让他三带1或2,那样更优。

    然后贪心爆搜,四带二, 四带两对, 四张炸, 三带一,三带一对, 三个单出,每一个情况都搜索一遍。

    剩下的一定就是单和对子了。

    再加上最优化剪枝过了。

    一开始回溯的时候用的栈存所有改变过的,然后再退栈。

    不知为何萎了。

    于是又参考了题解233.


    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    inline int read() {
        int res = 0;char ch=getchar();
        while(!isdigit(ch)) ch=getchar();
        while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48), ch=getchar();
        return res;
    }
    #define reg register
    
    int T, n;
    int hav[17];//how many cards at beginning, 14 means the king
    int ans;
    
    inline bool sanshun(int i) { 
        if (hav[i] >= 3 and hav[i%13+1] >= 3) return 1;
        return 0;
    }
    
    inline bool shuangshun(int i) {
        if (hav[i] >= 2 and hav[i+1] >= 2 and hav[(i+1)%13+1] >= 2) return 1;
        return 0;    
    }
    
    inline bool danshun(int i) {
        if (hav[i] >= 1 and hav[i+1] >= 1 and hav[i+2] >= 1 and hav[i+3] >= 1 and hav[(i+3)%13+1] >= 1) return 1;
        return 0;    
    }
    
    inline int four() {
        for (reg int i = 1 ; i <= 14 ; i ++)
            if (hav[i] >= 4) return i;
        return -1;
    }
    
    inline int three() {
        for (reg int i = 1 ; i <= 14 ; i ++)
            if (hav[i] >= 3) return i;
        return -1;
    }
    
    void dfs(int dep, int lef) {
        if (dep >= ans) return;
        if (!lef) {ans = dep;return ;}
        for (reg int i = 3 ; i <= 12 ; i ++) { //双顺子 
            if (shuangshun(i)) 
            {
                int k = i;
                while(hav[k] >= 2 and k != 2) 
                {
                    hav[k] -= 2;
                    if (k - i + 1 >= 3) dfs(dep + 1, lef - (k - i + 1));
                    k++;
                    if (k == 14) k = 1;
                }
                if (k == 1) k = 14; // 13 -> 1
                else if (k == 2) k = 15; // 1 -> 2
                dfs(dep + 1, lef - (k - i));
                if (k == 15) k--, hav[1] += 2;
                for (reg int j = i ; j <= k - 1 ; j ++) hav[j] += 2;
            }
        }
        for (reg int i = 3 ; i <= 10 ; i ++) { //单顺子 
            if (danshun(i))
            {
                int k = i;
                while(hav[k] >= 1 and k != 2) 
                {
                    hav[k]--;
                    if (k - i + 1 >= 5) dfs(dep + 1, lef - (k - i + 1));
                    k++;
                    if (k == 14) k = 1;
                }
                if (k == 1) k = 14;
                else if (k == 2) k = 15;
                dfs(dep + 1, lef - (k - i));
                if (k == 15) k--, hav[1] ++;
                for (reg int j = i ; j <= k - 1 ; j ++) hav[j] ++;
            }
        }
        //四带~~~
        int k = four(); 
        if (k != -1) 
        {
            hav[k] -= 4;
            for (reg int i = 1 ; i <= 14 ; i ++)
            {
                if (!hav[i]) continue;
                for (reg int j = 1 ; j <= 14 ; j ++)
                {
                    if (i == j or !hav[j]) continue;
                    if (hav[i] >= 2 and hav[j] >= 2) //四带两对 
                    {
                        hav[i] -= 2, hav[j] -= 2;
                        dfs(dep + 1, lef - 8);
                        hav[i] += 2, hav[j] += 2;
                    }
                    if (hav[i] and hav[j]) //四带两张 
                    {
                        hav[i]--, hav[j]--;
                        dfs(dep + 1, lef - 6);
                        hav[i]++, hav[j]++;
                    }
                }
            }
            dfs(dep + 1, lef - 4);//comboon! 
            hav[k] += 4;
        }
        //三带~~~
        k = three();
        if (k != -1) {
            hav[k] -= 3;
            for (reg int i = 1 ; i <= 14 ; i ++) 
            {
                if (hav[i] >= 2)
                {
                    hav[i] -= 2;
                    dfs(dep + 1, lef - 5);
                    hav[i] += 2;
                }
                if (hav[i]) 
                {
                    hav[i]--;
                    dfs(dep + 1, lef - 4);
                    hav[i]++;
                }            
            }
            dfs(dep + 1, lef - 3);//单三 
            hav[k] += 3;
        }
        //现在只剩下对和单了
        int sum = 0;
        for (reg int i = 1 ; i <= 14 ; i ++)
            if (hav[i]) sum ++;
        dfs(dep + sum, 0);
    }
    
    int main()
    {
        T = read(), n = read();
        while(T--)
        {
            memset(hav, 0, sizeof hav);
            for (reg int i = 1 ; i <= n ; i ++) {
                int x = read(), y = read();
                if (x != 0) hav[x]++;
                else hav[14]++;
            }
            ans = 14;
            dfs(0, n);
            printf("%d
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    AOP入门之静态代理
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
    C# 6 与 .NET Core 1.0 高级编程
  • 原文地址:https://www.cnblogs.com/BriMon/p/9545149.html
Copyright © 2011-2022 走看看