NOIP 2015 斗地主

【分析】
这题真是令人手动再见
玩了这么多年斗地主现在才知道王还能被三带一带走。
其实题目给的还算清楚,都是我惯性思维惹的祸qwqqq。
这道题要用 搜索+贪心+小小最优性剪枝
搜索搜三种情况:顺子,连对,三张连对
然后贪心:优先四带连对,然后四带二(注意四带二两种情况,在代码里有体现:带的两张有可能是相同牌),然后三带二,三带一,最后是单排,对子,三张,炸弹,直接模拟统计计入答案。
下了一堆测试数据才过,代码中间三段其实可以压缩,因为本质相同,但是当时脑抽,人又懒qwqqq。


【代码】

//NOIP 2015 斗地主 
#include<iostream>
#include<cstdio>
#include<cstring>
#define fo(i,j,k) for(i=j;i<=k;i++) 
using namespace std;
const int inf=1000000;
int n,m,T,ans;
int b[16],c[5];
inline int czy()
{
    int i,j,k,tot=0;
    memset(c,0,sizeof c);
    fo(i,0,14) c[b[i]]++;
    while(c[4] && c[1]>1) c[4]--,c[1]-=2,tot++;
    while(c[4] && c[2]>1) c[4]--,c[2]-=2,tot++;
    while(c[4] && c[2]) c[4]--,c[2]--,tot++;
    while(c[3] && c[1]) c[3]--,c[1]--,tot++;
    while(c[3] && c[2]) c[3]--,c[2]--,tot++;
    return c[1]+c[2]+c[3]+c[4]+tot;
}
inline void dfs(int stp,int yu)
{
    if(stp==ans) return;
    if(yu==0) {ans=stp;return;}
    bool flag=0;
    int s,e,i,j,k,tot=0;
    fo(i,3,10)
    {
        fo(j,i,i+4)
            if(!b[j]) break;
        if(j==i+5)
        {
            s=i;
            fo(j,i,15)
            {
                if(!b[j])
                {
                    flag=1;
                    e=j-1;
                    break;
                }
            }   
        }
        else i=j;
        if(flag)
        {
            flag=0;
            tot++;
            int l;
            fo(l,4,e-s)
            {
                fo(i,s,e-l)
                {
                    fo(j,i,i+l)
                      b[j]--;
                    dfs(stp+1,yu-l-1);
                    fo(j,i,i+l)
                      b[j]++;
                }
            }
            i=e;
        }
    }
    flag=0;
    fo(i,3,12)    //连对 
    {
        fo(j,i,i+2)
          if(b[j]<2) break;
        if(j==i+3)
        {
            s=i;
            fo(j,i,15)
            {
              if(b[j]<2)
              {
                e=j-1;
                flag=1;
                break;
              }
            }
        }
        else i=j;
        if(flag)
        {
            flag=0;
            tot++;
            int l;
            fo(l,2,e-s)
            {
                fo(i,s,e-l)
                {
                    fo(j,i,i+l)
                      b[j]-=2;
                    dfs(stp+1,yu-2*(l+1));
                    fo(j,i,i+l)
                      b[j]+=2;
                }
            }
            i=e;
        }
    }
    flag=0;
    fo(i,3,13)     //三顺子
    {
        fo(j,i,i+1)
          if(b[j]<3) break;
        if(j==i+2)
        {
            s=i;
            fo(j,i,15)
            {
              if(b[j]<3)
              {
                e=j-1;
                flag=1;
                break;
              }
            }
        }
        else i=j;
        if(flag)
        {
            flag=0;
            tot++;
            int l;
            fo(l,1,e-s)
            {
                fo(i,s,e-l)
                {
                    fo(j,i,i+l)
                      b[j]-=3;
                    dfs(stp+1,yu-3*(l+1));
                    fo(j,i,i+l)
                      b[j]+=3;
                }
            }
            i=e;
        }
    }
    ans=min(ans,czy()+stp);
}
int main()
{
    int i,j,k,x;
    scanf("%d%d",&T,&n);
    while(T--)
    {
        int f=0;
        int tmp;
        ans=inf;
        memset(b,0,sizeof b);
        fo(i,1,n)
        {
            scanf("%d",&tmp);
            if(tmp==1) tmp=14;
            scanf("%d",&x);
            b[tmp]++;
        }
        dfs(0,n);
        printf("%d\n",ans);
//        if(k==65) return 0;
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值