[LOJ2422]【NOIP2015】斗地主

大名鼎鼎的NOIP2015D1T3

题意:

由于一些众所周知的原因,没有完整题面……

给你一副斗地主的手牌(牌数<=23),问最少要几次能出完;

包含双王,没有癞子,连对要三连对以上,可以直接出三张同点数的牌(三对),可以出连着的三对,也可以三带一,三带二,但不能出飞机,可以四张带一对或两张单牌。

题解:

神题啊……orz……虽然写起来并不麻烦,但是当年这个神之题面真是雷倒了无数选手……

提前来做的原因是今天xfz出了一道毒瘤题(密码:yxqak)……是这题的弱化版(其实是道水题啦),本蒟蒻看到题面就吓傻了不敢打,改完题来膜一下原题……

首先注意到花色和点数大小是没用的(王也可以被带着出),且出牌时除非出顺子(连对,连三对),否则出牌的顺序是不会影响到最后答案的;

并且牌数很少(毕竟是斗地主嘛……),最多只会有四个顺子,所以可以直接暴力dfs把所有顺子找出来,枚举怎么出每一个顺子,然后再贪心处理当前的出牌情况;

很容易想到把牌组合起来出越多越好,贪心优先四带二,三带二,三带一,剩余的炸弹,三对,对子和单张直接出掉;

于是就……做完了。

ps:然而实际上由于本题数据太小,爆搜可以轻松通过

(听说欢乐斗地主上100w豆即可一秒切掉此题)

代码:

  1 #include<algorithm>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<cmath>
  6 #include<queue>
  7 #define inf 2147483647
  8 #define eps 1e-9
  9 using namespace std;
 10 typedef long long ll;
 11 int t,n,x,y,ans,num[17],tot[5];
 12 int gao(){
 13     int ret=0;
 14     memset(tot,0,sizeof(tot));
 15     for(int i=3;i<=16;i++){
 16         tot[num[i]]++;
 17     }
 18     while(tot[4]&&tot[2]>=2){
 19         tot[4]--;
 20         tot[2]-=2;
 21         ret++;
 22     }
 23     while(tot[4]&&tot[1]>=2){
 24         tot[4]--;
 25         tot[1]-=2;
 26         ret++;
 27     }
 28     while(tot[4]&&tot[2]){
 29         tot[4]--;
 30         tot[2]--;
 31     }
 32     while(tot[3]&&tot[2]){
 33         tot[3]--;
 34         tot[2]--;
 35         ret++;
 36     }
 37     while(tot[3]&&tot[1]){
 38         tot[3]--;
 39         tot[1]--;
 40         ret++;
 41     }
 42     return ret+tot[1]+tot[2]+tot[3]+tot[4];
 43 }
 44 void dfs(int nw){
 45     if(nw>=ans)return;
 46     ans=min(ans,nw+gao());
 47     for(int i=3,j;i<=14;i++){
 48         j=i;
 49         while(num[j]>=3&&j<=14)j++;
 50         if(j-i>=2){
 51             for(int k=i+1;k<j;k++){
 52                 for(int l=i;l<=k;l++){
 53                     num[l]-=3;
 54                 }
 55                 dfs(nw+1);
 56                 for(int l=i;l<=k;l++){
 57                     num[l]+=3;
 58                 }
 59             }
 60         }
 61     }
 62     for(int i=3,j;i<=14;i++){
 63         j=i;
 64         while(num[j]>=2&&j<=14)j++;
 65         if(j-i>=3){
 66             for(int k=i+2;k<j;k++){
 67                 for(int l=i;l<=k;l++){
 68                     num[l]-=2;
 69                 }
 70                 dfs(nw+1);
 71                 for(int l=i;l<=k;l++){
 72                     num[l]+=2;
 73                 }
 74             }
 75         }
 76     }
 77     for(int i=3,j;i<=14;i++){
 78         j=i;
 79         while(num[j]&&j<=14)j++;
 80         if(j-i>=5){
 81             for(int k=i+4;k<j;k++){
 82                 for(int l=i;l<=k;l++){
 83                     num[l]--;
 84                 }
 85                 dfs(nw+1);
 86                 for(int l=i;l<=k;l++){
 87                     num[l]++;
 88                 }
 89             }
 90         }
 91     }
 92 }
 93 int main(){
 94     scanf("%d%d",&t,&n);
 95     while(t--){
 96         ans=inf;
 97         memset(num,0,sizeof(num));
 98         for(int i=1;i<=n;i++){
 99             scanf("%d%d",&x,&y);
100             if(!x)x=16;
101             if(x==1)x=14;
102             if(x==2)x=15;
103             num[x]++;
104         }
105         dfs(0);
106         printf("%d\n",ans);
107     }
108     return 0;
109 }
posted @ 2018-10-29 19:25  DCDCBigBig  阅读(346)  评论(3编辑  收藏  举报