洛谷 題解 P2540 【鬥地主加強版】

【分析】

暴力搜順子,貪心出散牌

爲何順子要暴力?c++

玩過鬥地主的都知道,並非出越長的順子越好,若是你有一組手牌,3,4,5,6,7,6,7,8,9,10,你一下把最長的出了去,你會單兩張牌,不如出兩個順子,因此順子要暴力。spa

貪心打散牌

這是核心所在,也是不超時的緣由。code

能夠先統計一下不一樣牌個數的組數,而後再出牌,blog

那如何打出最優解?排序

首先必定要先出四帶二,再出三帶一,這是很容易想到的,由於四帶能夠帶走兩張。get

這樣寫正的行了嗎?博客

固然不行,原題的隨機數額能夠過,加強版的必須考慮拆牌,並且還要考慮王炸的特殊狀況,王算單牌,但能夠當對出,明確這一點。it

拆牌

何時該拆牌呢,對牌除了四帶的狀況不能拆,由於拆了可能多打一手牌。io

仔細想一想,三張和炸在單牌和對牌不少的時候是不能拆的,拆了就多大。class

當單牌和對牌數的和小於三張和炸的和,這就能夠拆了

由於這時不拆的話沒得帶,只能單出,若是把三張拆成一單和一對,讓其他的三張和炸帶走,就會少一步。

四張的同理。

具體貪心過程(按優先級排序)

  • 把一個炸拆成3張和單牌,再出一組四帶二單和三帶一

  • 把一組三張拆成一對和一單,再出一組四帶二單和三帶二

  • 三四張的比單牌和對牌多,拆着打

  • 還多繼續拆

  • 四帶兩單

  • 四帶兩對

  • 對當作兩單再四帶

  • 三張的太多了拆三張

  • 把一組三張拆成單和對,再出三帶一和三帶二

  • 三帶一

  • 三帶二

還剩三張和炸,組合出

  • 把兩個三張拆成兩個對和兩個單,再出四帶兩對和四帶兩單

  • 把一個炸拆成一對和兩單,再出三帶二和四帶兩單

  • 把一個炸拆成兩對,再出兩組三帶一對

  • 同上,把一組三張拆成單和對,再出三帶一和三帶二

  • 把一個炸拆成兩對,再出一組四帶兩對

  • 有雙王一塊出

  • 出單牌

【代碼】

#include<bits/stdc++.h>
using namespace std;
int T,n;
int pai[15];
int ans=0x3f3f3f3f;
inline int read()
{
    int tot=0,f=1;char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        tot=tot*10+c-'0';
        c=getchar();
    }
    return tot*f;
}
inline bool check()
{
    for(int i=1;i<=14;i++)
        if(pai[i])return false;
    return true;
}
inline int sp()
{
    bool flag=(pai[14]==2?1:0);
    int c[5],tot=0;
    memset(c,0,sizeof(c));
    c[1]+=pai[14];
    for(int i=1;i<=13;i++)c[pai[i]]++;
    /*for(int i=1;i<=4;i++)
        cout<<c[i]<<" ";
    cout<<endl;*/
    while(c[3]==0&&c[1]==1&&c[2]==1&&c[4]>1)tot+=2,c[4]-=2,c[1]--,c[2]--;
    while(c[2]==0&&c[1]==1&&c[4]==1&&c[3]>1)tot+=2,c[3]-=2,c[1]--,c[4]--;
    if(c[3]+c[4]>c[1]+c[2])while(c[4]>0&&c[2]>0&&c[3]>0)tot++,c[2]--,c[3]--,c[1]++,c[4]--;
    if(c[3]+c[4]>c[1]+c[2])while(c[4]>0&&c[1]>0&&c[3]>0)tot++,c[1]--,c[3]--,c[2]++,c[4]--;
    while(c[4]>0&&c[1]>1)tot++,c[4]--,c[1]-=2;
    while(c[4]>0&&c[2]>1)tot++,c[4]--,c[2]-=2;
    while(c[4]>0&&c[2]>0)tot++,c[4]--,c[2]--;
    if(c[3]%3==0&&c[1]+c[2]<=1)while(c[3]>2)tot+=2,c[3]-=3;
    while(c[3]>0&&c[2]>0)tot++,c[3]--,c[2]--;
    while(c[3]>0&&c[1]>0)tot++,c[3]--,c[1]--;
    while(c[4]>1&&c[3]>1)tot+=2,c[3]-=2,c[4]-=2;
    while(c[4]>1&&c[3]>0)tot+=2,c[3]--,c[4]-=2;
    while(c[3]>1&&c[4]>0)tot+=2,c[4]--,c[3]-=2;
    while(c[4]>1)tot++,c[4]-=2;
    while(c[3]>2)tot+=2,c[3]-=3;
    /*for(int i=1;i<=4;i++)
        cout<<c[i]<<" ";
    cout<<endl;*/
    if(c[1]>=2&&flag)return tot+c[2]+c[3]+c[4]+c[1]-1;
    else return tot+c[1]+c[2]+c[3]+c[4];
}
inline void dfs(int cnt)
{
    if(cnt>=ans)return;
    if(check())
    {
        ans=min(ans,cnt);
    }
    int temp=sp();
    /*for(int i=1;i<=14;i++)
        cout<<pai[i]<<" ";cout<<endl; */
    ans=min(temp+cnt,ans);
    for(int i=1;i<=12;i++)
    {
        if(pai[i]<3)continue;
        for(int j=i+1;j<=12;j++)
        {
            if(pai[j]<3)break;
            if(j-i+1>=2)
            {
                for(int k=i;k<=j;k++)pai[k]-=3;
                dfs(cnt+1);
                for(int k=i;k<=j;k++)pai[k]+=3;
            }
        }
    }
    for(int i=1;i<=12;i++)
    {
        if(pai[i]<2)continue;
        for(int j=i+1;j<=12;j++)
        {
            if(pai[j]<2)break;
            if(j-i+1>=3)
            {
                for(int k=i;k<=j;k++)pai[k]-=2;
                dfs(cnt+1);
                for(int k=i;k<=j;k++)pai[k]+=2;
            }
        }
    }
    for(int i=1;i<=12;i++)
    {
        if(!pai[i])continue;
        for(int j=i+1;j<=12;j++)
        {
            if(!pai[j])break;
            if(j-i+1>=5)
            {
                for(int k=i;k<=j;k++)pai[k]--;
                dfs(cnt+1);
                for(int k=i;k<=j;k++)pai[k]++;
            }
        }
    }
}
int main()
{
    //freopen("testdata.in","r",stdin);
    T=read();n=read();
    while(T--)
    {
        memset(pai,0,sizeof(pai));
        ans=0x3f3f3f3f;
        int ds,hs;
        for(int i=1;i<=n;i++)
        {
            ds=read();hs=read();
            if(ds>=3&&ds<=13)pai[ds-2]++;
            else if(ds==0&&hs==1)pai[14]++;
            else if(ds==0&&hs==2)pai[14]++;
            else pai[ds+11]++;
        }
        dfs(0);
        cout<<ans<<endl;
    }
    return 0;
}

參考博客:https://www.luogu.org/blog/user40673/solution-p2540

相關文章
相關標籤/搜索