NOIP2015 斗地主 搜索+贪心

版权声明:本文为DyingShu原创文章,转载请注明出处哦。 https://blog.csdn.net/DyingShu/article/details/82251487

传送门1——斗地主普通版
传送门2——斗地主增强版,慎入

有点恶心,特别是增强版

题解:大爆搜,搜索出顺子,贪心出散牌
据说加强版的标程都是贪心把除了顺子之外的散牌通过拆牌,贪心一次出完的。。而我太菜,只会出对子和单牌233
最后用几个奇奇怪怪的剪枝过了

#include<cstdio>
#include<algorithm>
#define re register
#define un unsigned
using namespace std;
const int MAXN = 20;

int T, n;

int Rest, Ans;
int Card[MAXN], Num[MAXN];

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int k = 0; char ch = nc();
    while(ch < '0' || ch > '9') ch = nc();
    while(ch >= '0' && ch <= '9') k = (k<<3) + (k<<1) + ch - '0', ch = nc();
    return k;
}

inline void Change(int u, int k){
    Num[Card[u]]--; Card[u] += k; Num[Card[u]]++;
}

void dfs(int u){ //已走u步
//	if(u >= Ans) return;
    if(u + Num[3] + Num[4] >= Ans) return; //奇奇怪怪的剪枝,至今不明白
    Ans = min(Ans, u + Num[1] + Num[2] + Num[3] + Num[4]);
    //单顺子
    if(Num[1] + Num[2] + Num[3] + Num[4] >= 5)
    for(int len = Num[1] + Num[2] + Num[3] + Num[4]; len >= 5; len--){
        for(int i = 2, j; i + len - 1 <= 13; i++){
            for(j = i; j <= i + len - 1; j++) if(Card[j] < 1) break;
            if(j > i + len - 1){
                for(int j = i; j <= i + len - 1; j++) Change(j, -1);
                dfs(u + 1);
                for(int j = i; j <= i + len - 1; j++) Change(j, 1);
            }
        }
    }
    //双顺子
    if(Num[2] + Num[3] + Num[4] >= 3)
    for(int len = Num[2] + Num[3] + Num[4]; len >= 3; len--){
        for(int i = 2, j; i + len - 1 <= 13; i++){
            for(j = i; j <= i + len - 1; j++) if(Card[j] < 2) break;
            if(j > i + len - 1){
                for(int j = i; j <= i + len - 1; j++) Change(j, -2);
                dfs(u + 1);
                for(int j = i; j <= i + len - 1; j++) Change(j, 2);
            }
        }
    }
    //三顺子
    if(Num[3] + Num[4] >= 2)
    for(int len = Num[3] + Num[4]; len >= 2; len--){
        for(int i = 2, j; i + len - 1 <= 13; i++){
            for(j = i; j <= i + len - 1; j++) if(Card[j] < 3) break;
            if(j > i + len - 1){
                for(int j = i; j <= i + len - 1; j++) Change(j, -3);
                dfs(u + 1);
                for(int j = i; j <= i + len - 1; j++) Change(j, 3);
            }
        }
    }

    if(Num[4]) for(int i = 1; i <= 13; i++){
        if(Card[i] == 4){
            Change(i, -4);
            //四带二对
            if(Num[2] + Num[3] > 1 || Num[4])
            for(int j = 1; j <= 13; j++){
                if(Card[j] >= 2){
                    Change(j, -2);
                    for(int k = j; k <= 13; k++){
                        if(Card[k] >= 2){
                            Change(k, -2);
                            dfs(u + 1);
                            Change(k, 2);
                        }
                    }
                    Change(j, 2);
                }
            }
            //四带一对
            if(Num[2] || Num[3] || Num[4])
            for(int j = 0; j <= 13; j++){
                if(Card[j] >= 2){
                    Change(j, -2);
                    dfs(u + 1);
                    Change(j, 2);
                }
            }
            //四带二
            for(int j = 0; j <= 13; j++){
                if(Card[j]){
                    Change(j, -1);
                    for(int k = j + 1; k <= 13; k++){
                        if(Card[k]){
                            Change(k, -1);
                            dfs(u + 1);
                            Change(k, 1);
                        }
                    }
                    Change(j, 1);
                }
            }
            dfs(u + 1);
            Change(i, 4);
        }
    }
    
    if(Num[3]) for(int i = 1; i <= 13; i++){
        if(Card[i] == 3){
            Change(i, -3);
            //三带二
            if(Num[2] || Num[3] || Num[4])
            for(int j = 1; j <= 13; j++){
                if(j == i) continue;
                if(Card[j] >= 2){
                    Change(j, -2);
                    dfs(u + 1);
                    Change(j, 2);
                }
            }
            //三带一
            for(int j = 0; j <= 13; j++){
                if(j == i) continue;
                if(Card[j] >= 1){
                    Change(j, -1);
                    dfs(u + 1);
                    Change(j, 1);
                }
            }
            dfs(u + 1);
            Change(i, 3);
        }
    }
    return;
}

int main(){
    T = read(), n = read();
    while(T--){
        Ans = n;
        for(int i = 0; i <= 13; i++) Card[i] = 0;
        for(int i = 0; i <= 4; i++) Num[i] = 0;
        for(int i = 1; i <= n; i++){
            int x = read(); read();
            if(x == 0) Card[0]++;
            else if(x == 1) Card[13]++;
            else Card[x - 1]++;
        }
        for(int i = 0; i <= 13; i++){
            Num[Card[i]]++;
        }
        dfs(0);
        printf("%d\n", Ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/DyingShu/article/details/82251487
今日推荐