P2668 斗地主

复习历年大模拟题系列

具体的做法框架大家都懂,就是一个card数组存你的牌,然后忽略所有的花色,然后就是一个自带card数组的dfs。

核心做法还是那十个字:暴力枚顺子,贪心出散牌

顺子什么的用回溯法的框架去解决,三带四带的各种情况也用回溯法的样子去解决,最后的散牌直接出单张或者出对即可。

增强版的好像挺难过的,好多毒瘤数据,我就不去了。

这道题别的没什么,只是注意枚举所有的可能性。这道题应该不会T吧。。。

有几个坑点顺便说一下:

  1. 对鬼可以当对子来打

  2. 有四带一这种情况

emmm好像没有了。

提醒:写搜索的时候最好就要想想剪枝,比如这里附带的最优性剪枝剪一剪就很舒服

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 25;
const int order[15] = {0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 1, 2, 0};
const int INF = 0x3f3f3f3f;
int card[maxn];
int n, ans;
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0', ch = getchar();
    return s *ans;
}
void dfs(int left, int res)
{
    if(res >= ans) return;
    if(left == 0)
    {
        ans = std::min(ans, res);
        return;
    }
    for(int i = 1; i <= 11; i++)// san shun zi
    {
        if(card[order[i]] >= 3)
        {
            int p;
            for(p = i + 1; p <= 12; p++)
            {
                if(card[order[p]] < 3) break;
            }
            p--;
            if(p - i + 1 >= 2)
            {
                for(int j = i; j <= p; j++) card[order[j]] -= 3;
                dfs(left - (p - i + 1) * 3, res + 1);
                for(int j = i; j <= p; j++) card[order[j]] += 3;
            }
        }
    }
    for(int i = 1; i <= 10; i++)// shuang shun zi
    {
        if(card[order[i]] >= 2)
        {
            int p;
            for(p = i + 1; p <= 12; p++)
            {
                if(card[order[p]] < 2) break;
            }
            p--;
            if(p - i + 1 >= 3)
            {
                for(int j = i; j <= p; j++) card[order[j]] -= 2;
                dfs(left - (p - i + 1) * 2, res + 1);
                for(int j = i; j <= p; j++) card[order[j]] += 2;
            }
        }
    }
    for(int i = 1; i <= 8; i++)// dan shun zi
    {
        if(card[order[i]] >= 1)
        {
            int p;
            for(p = i + 1; p <= 12; p++)
            {
                if(card[order[p]] < 1) break;
            }
            p--;
            if(p - i + 1 >= 5)
            {
                for(int j = i; j <= p; j++) card[order[j]]--;
                dfs(left - (p - i + 1), res + 1);
                for(int j = i; j <= p; j++) card[order[j]]++;
            }
        }
    }
    for(int i = 1; i <= 13; i++)// si dai
    {
        if(card[order[i]] >= 4)
        {
            card[order[i]] -= 4;
            for(int j = 1; j <= 14; j++)
            {
                if(card[order[j]] >= 2)
                {
                    card[order[j]] -= 2;
                    for(int k = j; k <= 14; k++)
                    {
                        if(card[order[k]] >= 2)
                        {
                            card[order[k]] -= 2;
                            dfs(left - 8, res + 1);// si dai liang dui
                            card[order[k]] += 2;
                        }
                    }
                    dfs(left - 6, res + 1);// si dai yi dui
                    card[order[j]] += 2;
                }
            }
            for(int j = 1; j <= 14; j++)
            {
                if(card[order[j]] >= 1)
                {
                    card[order[j]]--;
                    for(int k = j; k <= 14; k++)
                    {
                        if(card[order[k]] >= 1)
                        {
                            card[order[k]]--;
                            dfs(left - 6, res + 1);// si dai liang zhang
                            card[order[k]]++;
                        }
                    }
                    dfs(left - 5, res + 1);// si dai yi zhang
                    card[order[j]]++;
                }
            }
            dfs(left - 4, res + 1);// zha dan
            card[order[i]] += 4;
        }
    }
    for(int i = 1; i <= 13; i++)// san dai 
    {
        if(card[order[i]] >= 3)
        {
            card[order[i]] -= 3;
            for(int j = 1; j <= 14; j++)
            {
                if(card[order[j]] >= 2)
                {
                    card[order[j]] -= 2;
                    dfs(left - 5, res + 1);// san dai yi dui
                    card[order[j]] += 2;
                }
                if(card[order[j]] >= 1)
                {
                    card[order[j]]--;
                    dfs(left - 4, res + 1);// san dai yi zhang
                    card[order[j]]++;
                }
            }
            dfs(left - 3, res + 1);// san zhang pai
            card[order[i]] += 3;
        }
    }
    for(int i = 1; i <= 14; i++)
    {
        if(card[order[i]] == 1 || card[order[i]] == 2)
        {
            left -= card[order[i]];
            res++;
        }
    }
    if(left == 0) ans = std::min(ans, res);
}
int main()
{
    int T = read(); n = read();
    while(T--)
    {
        memset(card, 0, sizeof card);
        ans = INF;
        for(int i = 1; i <= n; i++)
        {
            int x = read(), y = read();
            card[x]++;
        }
        dfs(n, 0);
        printf("%d\n", ans);
    }
    return 0;
}

转载于:https://www.cnblogs.com/Garen-Wang/p/9892776.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值