Luogu2668 斗地主/Luogu2540 斗地主增强版

https://www.luogu.com.cn/problem/P2668

https://www.luogu.com.cn/problem/P2540

搜索

我们搜索顺子,最优选择应该是先搜单顺或者双顺,再搜三顺(毕竟三张牌用处更大)

顺子可以从长的搜到短的

最优性剪枝就不用多说了吧

然后每搜到一个状态,对散牌进行处理

首先枚举把四张牌三张牌拆开的情况(用了六重循环

由于我们枚举了拆开的情况,剩下的牌都是整份整份打出的(三张牌就必须三张牌一起打出,不能拆成\(1+2,1+1+1\)

然后先用四带二,把单牌对牌尽量拿走

比较讨厌的是小王大王,只有其中一张与单牌无异,两张的话,如果还有四张牌,那么让四张牌把讨厌的小王大王一块儿吃了,如果没有的话,到三张牌的时候再处理

如果有多余的一张牌两张牌,特判即可

接下来剩余的四张牌都是炸弹

好了,然后是三带一三带二和剩余的散牌

\(S_i\)表示含有\(i\)张的牌的种类数量,\(a_0\)表示小王大王的数量

\[ans=ans+ \begin{cases} S_3 & (S_1+S_2+a_0 \le S_3)\\ S_1+S_2+a_0 & (S_1+S_2+a_0 > S_3 且 a_0<2)\\ S_1+S_2+a_0 & (S_1+S_2+a_0 = S_3+1 且 a_0=2)\\ S_1+S_2+a_0-1 & (S_1+S_2+a_0 > S_3+1 且 a_0=2)\\ \end{cases} \]

第三种情况一开始没判,导致计算出来的数值反而比标准答案小,因为小王大王其中一张被三带一了,所以火箭没用

\(Code:\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int T,n,x,y,ans,a[14],rk[5],k[5];
int check()
{
    int g=0;
    //四带二
    if (k[4]<=(k[1] >> 1))
    {
        g+=k[4];
        k[1]-=k[4] << 1;
        k[4]=0;
    } else
    {
        g+=k[1] >> 1;
        k[4]-=k[1] >> 1;
        k[1]&=1;
    }
    if (k[4]<=(k[2] >> 1))
    {
        g+=k[4];
        k[2]-=k[4] << 1;
        k[4]=0;
    } else
    {
        g+=k[2] >> 1;
        k[4]-=k[2] >> 1;
        k[2]&=1;
    }
    int a0=a[0];
    if (a0 && k[4])
    {
        if (a0==1)
        {
            if (k[1])
                g++,k[4]--,k[1]--; else
                k[1]++;
        } else
            g++,k[4]--;
        a0=0;
    }
    if (k[4])
    {
        if (k[2])
        {
            k[2]=0;
            k[4]--;
            g++;
        }
    }
    g+=k[4];
    //三带二、三带一、单牌、对牌
    if (k[3]>=k[1]+k[2]+a0)
        g+=k[3]; else
        g+=k[1]+k[2]+a0-(int)(a0==2 && k[1]+k[2]>=k[3]);
    return g;
}
int ck()
{
    int g=105;
    memset(rk,0,sizeof(rk));
    for (int i=1;i<=13;i++)
        rk[a[i]]++;
    for (int i=0;i<=rk[4];i++)
        for (int i2=0;i2<=rk[4]-i;i2++)
            for (int i3=0;i3<=rk[4]-i-i2;i3++)
                for (int i4=0;i4<=rk[4]-i-i2-i3;i4++)
                    for (int j=0;j<=rk[3];j++)
                        for (int j2=0;j2<=rk[3]-j;j2++)
                        {
                            memcpy(k,rk,sizeof(rk));
                            k[4]-=i,k[1]+=i,k[3]+=i;//4=1+3
                            k[4]-=i2,k[2]+=i2 << 1;//4=2+2
                            k[4]-=i3,k[1]+=i3 << 2;//4=1+1+1+1
                            k[4]-=i4,k[1]+=i4 << 1,k[2]+=i4;//4=1+1+2
                            k[3]-=j,k[1]+=j,k[2]+=j;//3=1+2
                            k[3]-=j2,k[1]+=j2*3;//3=1+1+1
                            g=min(g,check());
                        }
    return g;
}
void dfs(int cs)
{
    if (cs>=ans)
        return;
    int o=ck();
    ans=min(ans,cs+o);
    if (!o)
        return;
    //双顺
    int s[14];
    s[13]=(int)(a[13]>=2);
    for (int i=12;i>=2;i--)
        if (a[i]<2)
            s[i]=0; else
            s[i]=s[i+1]+1;
    for (int i=2;i<=11;i++)
    {
        for (int j=s[i];j>=3;j--)
        {
            for (int k=i;k<i+j;k++)
                a[k]-=2;
            dfs(cs+1);
            for (int k=i;k<i+j;k++)
                a[k]+=2;
        }
    }
    //单顺
    s[13]=(int)(a[13]>=1);
    for (int i=12;i>=2;i--)
        if (!a[i])
            s[i]=0; else
            s[i]=s[i+1]+1;
    for (int i=2;i<=9;i++)
    {
        for (int j=s[i];j>=5;j--)
        {
            for (int k=i;k<i+j;k++)
                a[k]--;
            dfs(cs+1);
            for (int k=i;k<i+j;k++)
                a[k]++;
        }
    }
    //三顺
    s[13]=(int)(a[13]>=3);
    for (int i=12;i>=2;i--)
        if (a[i]<3)
            s[i]=0; else
            s[i]=s[i+1]+1;
    for (int i=2;i<=12;i++)
    {
        for (int j=s[i];j>=2;j--)
        {
            for (int k=i;k<i+j;k++)
                a[k]-=3;
            dfs(cs+1);
            for (int k=i;k<i+j;k++)
                a[k]+=3;
        }
    }
}
int main()
{
    scanf("%d%d",&T,&n);
    while (T --> 0)
    {
        memset(a,0,sizeof(a));
        for (int i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            if (x==1)
                x=13; else
            if (x)
                x--;
            a[x]++;
        }
        ans=ck();
        dfs(0);
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2020-09-10 15:35  GK0328  阅读(267)  评论(0编辑  收藏  举报