NOIP2015斗地主(搜索+模拟+贪心)

%%%Luan

题面就不说了,和斗地主一样,给一组牌,求最少打几次。

注意一点,数据随机,这样我们瞎搞一搞就可以过,虽然直接贪心可以证明是错的。

枚举方法,每次搜索按照(三顺子>二顺子>普通顺子)枚举一个进入下一层搜索。

在每层搜索中我们都要枚举打其他牌的方法,用贪心的结果+顺子数来更新答案。

具体方法是(想象你手里有这么多牌你该怎么打),枚举四代二,四代一,三代二,三代一,对和单。

注意我要带的必须是恰好两个或一个,不然会被随机数据hack。。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int di[20],cnt[20],ans,n,t,a,b;
inline int counting(){
    int jians=0;
    for(int i=1;i<=14;++i)di[i]=cnt[i];
    for(int i=1;i<=13;++i)
      if(di[i]>=4)
        for(int j=1;j<=14;++j)
          if(i!=j&&di[j]==2&&di[i]>=4)
            for(int k=j+1;k<=14;++k)
              if(k!=i&&di[k]==2){di[i]-=4;di[j]-=2;di[k]-=2;jians++;break;}
    for(int i=1;i<=13;++i)
      if(di[i]>=4)
        for(int j=1;j<=14;++j)
          if(i!=j&&di[j]==1&&di[i]>=4)
            for(int k=j+1;k<=14;++k)
              if(k!=i&&di[k]==1){di[i]-=4;di[j]--;di[k]--;jians++;break;} 
    for(int i=1;i<=13;++i)
      if(di[i]>=4)
        for(int j=1;j<=14;++j)
          if(i!=j&&di[j]==2){di[j]-=2;di[i]-=4;jians++;break;}
    for(int i=1;i<=13;++i)while(di[i]>=4)jians++,di[i]-=4;
    for(int i=1;i<=13;++i)
      if(di[i]>=3)
        for(int j=1;j<=14;++j)
          if(i!=j&&di[j]==2){if(di[i]<3)break;di[i]-=3;di[j]-=2;jians++;}
    for(int i=1;i<=13;++i)
      if(di[i]>=3)
        for(int j=1;j<=14;++j)
          if(i!=j&&di[j]==1){if(di[i]<3)break;di[j]--;di[i]-=3;jians++;} 
    for(int i=1;i<=13;++i)while(di[i]>=3)jians++,di[i]-=3;
    for(int i=1;i<=14;++i)while(di[i]>=2)jians++,di[i]-=2;
    for(int i=1;i<=14;++i)while(di[i])jians++,di[i]--;
    return jians;      
} 
void dfs(int deep){
    if(deep>=ans)return;
    for(int i=1;i<=14;++i){
        if(cnt[i])break;
        if(i==14){
            ans=deep;return;
        }
    }
//    for(int i=1;i<=14;++i)cout<<cnt[i]<<" ";cout<<"   ";
    int cmd=counting();//cout<<cmd<<endl;
    if(cmd+deep<ans)ans=cmd+deep;
    for(int i=1;i<=10;++i)if(cnt[i]>=3)
      for(int j=i+1;j<=12;++j){
          bool tag=0;
          for(int k=i;k<=j;++k)
              if(cnt[k]<3){
                  tag=1;
                break;
               }
          if(tag)break;
         for(int k=i;k<=j;++k)cnt[k]-=3;
         dfs(deep+1);
         for(int k=i;k<=j;++k)cnt[k]+=3;
       }
    for(int i=1;i<=10;++i)if(cnt[i]>=2)
      for(int j=i+2;j<=12;++j){
           bool tag=0;
           for(int k=i;k<=j;++k)
               if(cnt[k]<2){
                   tag=1;
                   break;
               }
        if(tag)break;
        for(int k=i;k<=j;++k)cnt[k]-=2;
        dfs(deep+1);
        for(int k=i;k<=j;++k)cnt[k]+=2;
      }
    for(int i=1;i<=8;++i)
      for(int j=i+4;j<=12;++j){
          bool tag=0;
          for(int k=i;k<=j;++k)
            if(!cnt[k]){
                  tag=1;
                  break;
            }
        if(tag)break;
        for(int k=i;k<=j;++k)--cnt[k];
        dfs(deep+1);
        for(int k=i;k<=j;++k)++cnt[k];
      }
}
int main(){
    scanf("%d%d",&t,&n);
    while(t--){
        memset(cnt,0,sizeof(cnt));
        for(int i=1;i<=n;++i){
            scanf("%d%d",&a,&b);
            if(a>=3||a<=13)cnt[a-2]++;
            if(a==0)cnt[14]++;
            if(a==1)cnt[12]++;
            if(a==2)cnt[13]++; 
        }
        ans=0x3f3f3f3f;
        dfs(0); 
        printf("%d
",ans); 
    }
    return 0; 
}
原文地址:https://www.cnblogs.com/ZH-comld/p/9599282.html