斗地主 (NOIP2015 Day1 T3)

            斗地主

:读入时注意将A作为第14张牌,因为它可以连在K后,

总体思路为 先出炸弹和四带二 再出三带一 再把对牌和单牌出完 记录并更新Answer,后枚举顺子,并继续向下搜索。

注意:弄明白题意,题目描述不太清楚。。。。另外,我觉的牌的花色只是能用来区分大小王。另外在整顺子之前也可以用贪心来搞其他类似四带二,三带一等的牌

 

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int Max = 20;
int T, N, Answer ;
int card [Max];
int Count [Max];
void DFS (int X)
{
    if (X > Answer ) return;
    int rest = 0;
    memset (Count, 0, sizeof (Count));
    for (int i = 0; i <= 14; i++)
        Count [card[i]]++;
    for (; Count [4]; )
    {
        Count [4]--;           //炸弹 
        rest++;
        if (Count [2] >= 2)    //判断能不能带2 
            Count [2] -= 2;
        else if (Count [1] >= 2)
            Count [1] -= 2;
    }
    for (; Count [3]; )  
    {
        Count [3]--;          //三张牌 
        rest++;
        if (Count [2])         //能不能带一 
            Count [2]--;
        else if (Count [1])
            Count [1]--;
    }
    if (card [0] && card [1] && Count [1] >= 2)    //看看剩下的单牌有没有王炸
        rest--;
    rest += Count [1] + Count [2];
    Answer = min (rest + X, Answer );
    for (int i = 3, j; i <= 14; ++i)         //单顺子
    {
        for (j = i; card [j] && j <= 14; ++j)  
        {
            card [j]--;
            if (j - i + 1 >= 5)        //如果剩下的牌多于五张 ,则向下搜索 
                DFS (X + 1);
        }
        for (; j > i; )
            card [--j]++;
    }
    for (int i = 3, j; i <= 15; ++i)        //双顺子 
    {
        for (j = i; card [j] >= 2 && j <= 14; ++j)
        {
            card [j] -= 2;
            if (j - i + 1 >= 3)
                DFS(X + 1);
        }
        for (; j > i; )
            card [--j] += 2;
    }
    for (int i = 3, j; i <= 15; ++i)     // 三顺子 
    {
        for (j = i; card [j] >= 3 && j <= 14; ++j)
        {
            card [j] -= 3;
            if (j - i + 1 >= 2)
                DFS (X + 1);
        }
        for (; j>i;)
            card [--j] += 3;
    }
}
int main()
{
    cin >> T >> N;
    int A, B;
    while (T--)
    {
        memset (card, 0, sizeof (card));
        Answer = N;
        for (int i = 1; i <= N; i++)
        {
            cin >> A >> B;
            if (A == 0) card [B - 1]++;    //王 要分开存 ,因为他们不能组成对子  ,不能当对牌出 
            else if (A == 1) card [14]++;    
            else card [A]++;
        }
        DFS (0);
        cout << Answer << endl;
    }
    return 0;
}

 

posted @ 2016-11-08 21:50  ZlycerQan  阅读(285)  评论(0编辑  收藏  举报