noip2015斗地主--毒瘤题

链接:https://www.luogu.org/problemnew/show/P2668

码量巨大搜索题(可能是我打的比较菜。。隔壁yzy大佬写的短还跑得快。。),首先想必先搜能一次打多张牌的比较优,因此先暴搜三顺子双顺子单顺子打那些排(注意同一张牌做起点能打多个顺子,这里被卡了2次。。),然后再暴搜四张牌打那些,并且顺便暴搜四张牌是否带排,如果是怎么带,然后三张牌同理,接着在打到两张牌时就可以统计答案了,有两张以上答案加2不然加1,然后就可以了,剪枝的话基本上就只加了一个搜索时步数大于当前答案return。复杂度自然很玄学,但跑的还是蛮快的。。

// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
int T,n,cnt[30],ans;
void shun1(int,int);void shun2(int,int);void shun3(int,int);void four(int,int);void three(int,int);
void dai2san(int pos,int ps,int foot,int used)
{
    if(pos>16)return;
    if(cnt[pos]>=1)
    {
        if(used==1){cnt[pos]--;four(ps+1,foot+1);cnt[pos]++;}
        else if(used==0)
        {
            if(cnt[pos]>=2){cnt[pos]-=2;four(ps+1,foot+1);cnt[pos]+=2;}
            cnt[pos]--;dai2san(pos+1,ps,foot,1);cnt[pos]++;
        }
    }
    dai2san(pos+1,ps,foot,used);
}
void dai2dui(int pos,int ps,int foot,int used)
{
    if(pos>15)return;
    if(cnt[pos]>=2)
    {
        if(used==1){cnt[pos]-=2;four(ps+1,foot+1);cnt[pos]+=2;}
        else if(used==0)
        {
            if(cnt[pos]>=4){cnt[pos]-=4;four(ps+1,foot+1);cnt[pos]+=4;}
            cnt[pos]-=2;dai2dui(pos+1,ps,foot,1);cnt[pos]+=2;
        }
    }
    dai2dui(pos+1,ps,foot,used);	
}
void dai1san(int pos,int ps,int foot)
{
    if(pos>16)return;
    if(cnt[pos]>=1)
    {
        cnt[pos]--;three(ps+1,foot+1);cnt[pos]++;
    }
    dai1san(pos+1,ps,foot);
}
void dai1dui(int pos,int ps,int foot)
{
    if(pos>15)return;
    if(cnt[pos]>=2)
    {
        cnt[pos]-=2;three(ps+1,foot+1);cnt[pos]+=2;
    }
    dai1dui(pos+1,ps,foot);
}
void get(int x)
{
    int nw=0;
    for(int i=3;i<=16;i++)
    {
        if(cnt[i])
        {
            if(cnt[i]<=2)nw++;
            else nw+=2;
        }
    }
    ans=min(ans,nw+x);
}
void three(int pos,int foot)
{
    if(foot>=ans)return;
    if(pos>15)
    {get(foot);return;}
    if(cnt[pos]>=3)
    {
        cnt[pos]-=3;
        three(pos+1,foot+1);
        dai1san(3,pos,foot);
        dai1dui(3,pos,foot);
        cnt[pos]+=3;
    }
    else three(pos+1,foot);
}
void four(int pos,int foot)
{
    if(foot>=ans)return;
    if(pos>15)
    {three(3,foot);return;}
    if(cnt[pos]>=4)
    {
        cnt[pos]-=4;
        four(pos+1,foot+1);
        dai2san(3,pos,foot,0);
        dai2dui(3,pos,foot,0);
        cnt[pos]+=4;
    }
    else four(pos+1,foot);
}
void shun1(int pos,int foot)
{
    if(foot>=ans)return;
    if(pos>=11)
    {
        four(3,foot);
        return;
    }
    int flag=pos-1;
    for(int i=pos;i<=14;i++)
    {
        if(cnt[i]>=1)flag=i;
        else break;
    }
    if(flag-pos>=4)
    {
        for(int i=pos;i<=flag;i++)cnt[i]--;
        for(int i=flag;i>pos+3;i--)
        {
            shun1(pos,foot+1);
            cnt[i]++;
        }
        cnt[pos]++,cnt[pos+1]++,cnt[pos+2]++,cnt[pos+3]++;
    }
    shun1(pos+1,foot);
}
void shun2(int pos,int foot)
{
    if(foot>=ans)return;
    if(pos>=13)
    {
        shun1(3,foot);
        return;
    }
    int flag=pos-1;
    for(int i=pos;i<=14;i++)
    {
        if(cnt[i]>=2)flag=i;
        else break;
    }
    if(flag-pos>=2)
    {
        for(int i=pos;i<=flag;i++)cnt[i]-=2;
        for(int i=flag;i>pos+1;i--)
        {
            shun2(pos,foot+1);
            cnt[i]+=2;
        }
        cnt[pos]+=2,cnt[pos+1]+=2;
    }
    shun2(pos+1,foot);	
}
void shun3(int pos,int foot)
{
    if(foot>=ans)return;
    if(pos>=14)
    {
        shun2(3,foot);
        return;
    }
    int flag=pos-1;
    for(int i=pos;i<=14;i++)
    {
        if(cnt[i]>=3)flag=i;
        else break;
    }
    if(flag-pos>=1)
    {
        for(int i=pos;i<=flag;i++)cnt[i]-=3;
        for(int i=flag;i>pos;i--)
        {
            shun3(pos,foot+1);
            cnt[i]+=3;
        }
        cnt[pos]+=3;
    }
    shun3(pos+1,foot);	
}
int main()
{
    int hs,num;int cas=0;
    //freopen("ot.txt","w",stdout);
    scanf("%d%d",&T,&n);
    while(T--)
    {
//		cas++;
        ans=1e9;
        memset(cnt,0,sizeof cnt);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&num,&hs);
            if(num==0)cnt[16]++;
            else if(num==1)cnt[14]++;
            else if(num==2)cnt[15]++;
            else cnt[num]++;
        //	if(cas==8)cout<<num<<" "<<hs<<endl;
        }
//		for(int i=3;i<=16;i++)cout<<cnt[i]<<" ";puts("");
        shun3(3,0);
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/caoyang1123/article/details/81587061
今日推荐