P2668斗地主40分AC剩下TLE代码求助
查看原帖
P2668斗地主40分AC剩下TLE代码求助
381926
_Anonymous_楼主2022/8/27 19:51

代码很长,注释不少,不知道哪里可以优化?希望不吝赐教

评测记录

// 

#include<iostream>
#include<iomanip>
#include<vector>
#include<queue>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<cstdio>
#include<string>
#include<algorithm>
#include<utility>
#include<limits.h>
#include<map>
#include<set>
using namespace std;

int t, n, ans;
int card_box[20];

void read()
{
    memset(card_box, 0, sizeof(card_box));
    for(int i = 0; i < n; i++)
    {
        int a, b;
        scanf("%d %d", &a, &b);
        switch (a)
        {
        case 0:
            card_box[15]++;
            break;
        
        case 1:
            card_box[14]++;
            break;

        default:
            card_box[a]++;
            break;
        }
    }
}

void dfs(int x)
{
    // 非最优,剪枝
    if(x >= ans)
    {
        return ;
    }

    // 单顺子 不带2不带王
    int dsz = 0;
    for(int i = 3; i < 15; i++)
    {
        // 单顺子断了
        if(card_box[i] < 1)
        {
            dsz = 0;
        }
        else
        {
            dsz++;
            // 可以出了
            if(dsz >= 5)
            {
                for(int j = i; j > i - dsz; j--)
                {
                    card_box[j]--;
                }
                dfs(x + 1);
                for(int j = i; j > i - dsz; j--)
                {
                   card_box[j]++;
                }
            }
        }
    }

    // 双顺子 不带2不带王
    int ssz = 0;
    for(int i = 3; i < 15; i++)
    {
        // 双顺子断了
        if(card_box[i] < 2)
        {
            ssz = 0;
        }
        else
        {
            ssz++;
            // 可以出了
            if(ssz >= 3)
            {
                for(int j = i; j > i - ssz; j--)
                {
                    card_box[j] -= 2;
                }
                dfs(x + 1);
                for(int j = i; j > i - ssz; j--)
                {
                   card_box[j] += 2;
                }
            }
        }
    }

    // 三顺子 不带2不带王
    int tsz = 0;
    for(int i = 3; i < 15; i++)
    {
        // 三顺子断了
        if(card_box[i] < 3)
        {
            ssz = 0;
        }
        else
        {
            ssz++;
            // 可以出了
            if(ssz >= 2)
            {
                for(int j = i; j > i - ssz; j--)
                {
                    card_box[j] -= 3;
                }
                dfs(x + 1);
                for(int j = i; j > i - ssz; j--)
                {
                   card_box[j] += 3;
                }
            }
        }
    }

    // 带牌
    for(int i = 2; i < 15; i++)
    {
        // 牌太少,过掉
        if(card_box[i] < 3)
        {
            continue;
        }

        // 出三张,带牌
        card_box[i] -= 3;
        // 三带一,带单张
        for(int j = 2; j < 15; j++)
        {
            // 没牌/是自己无法带牌, 过掉
            if(j == i || card_box[j] < 1)
            {
                continue;
            }
            // 出掉被带的牌
            card_box[j]--;
            dfs(x + 1);
            card_box[j]++;
        }
        // 三带二,带一对
        for(int j = 2; j < 15; j++)
        {
            // 没对子/是自己无法带牌, 过掉
            if(j == i || card_box[j] < 2)
            {
                continue;
            }
            // 出掉被带的一对
            card_box[j] -= 2;
            dfs(x + 1);
            card_box[j] += 2;
        }
        card_box[i] += 3;

        // 三张过掉
        if(card_box[i] == 3)
        {
            continue;
        }
        // 出四张,带牌
        card_box[i] -= 4;
        // 四带二,带两张单牌
        for(int j = 2; j < 15; j++)
        {
            // 没牌/是自己无法带牌, 过掉
            if(j == i || card_box[j] < 1)
            {
                continue;
            }
            // 出掉被带的第一张单牌
            card_box[j]--;
            // 找第二张单牌
            for(int k = 2; k < 15; j++)
            {
                // 没单牌/已经带了/是自己无法带牌, 过掉
                if(k == i || k == j || card_box[k] < 1)
                {
                    continue;
                }
                // 出掉被带的第二张单牌
                card_box[k]--;
                dfs(x + 1);
                card_box[k]++;
            }
            card_box[j]++;
        }
        // 四带二,带两个对子
        for(int j = 2; j < 15; j++)
        {
            // 没对子/是自己无法带牌, 过掉
            if(j == i || card_box[j] < 2)
            {
                continue;
            }
            // 出掉被带的第一个对子
            card_box[j] -= 2;
            // 找第二个对子
            for(int k = 2; k < 15; j++)
            {
                // 没对子/已经带了/是自己无法带牌, 过掉
                if(k == i || k == j || card_box[k] < 2)
                {
                    continue;
                }
                // 出掉被带的第二张单牌
                card_box[k] -= 2;
                dfs(x + 1);
                card_box[k] += 2;
            }
            card_box[j] += 2;
        }
        card_box[i] += 4;
    }

    // 把剩下的单牌出完
    for(int i = 2; i <= 15; i++)
    {
        if(card_box[i])
        {
            x++;
        }
    }
    ans = min(ans, x);
}

int main()
{
    cin >> t >> n;
    while(t--)
    {
        ans = 1 << 30;
        read();
        dfs(0);
        printf("%d\n", ans);
    }
}
2022/8/27 19:51
加载中...