NOIP2015 斗地主


题目描述
牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方
片的A 到K 加上大小王的共54 张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据
牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产
生影响。每一局游戏中,一副手牌由n 张牌组成。游戏者每次可以根据规定的牌型进行出
牌,首先打光自己的手牌一方取得游戏的胜利。现在,牛牛只想知道,对于自己的若干组
手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。需要注意的是,
本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。具体规则如下:

输入
第一行包含用空格隔开的2 个正整数T,N,表示手牌的组数以及每组手牌的张数。
接下来T 组数据,每组数据N 行,每行一个非负整数对Ai,Bi,表示一张牌,其中Ai
表示牌的数码,Bi 表示牌的花色,中间用空格隔开。特别的,我们用1 来表示数码A,11
表示数码J,12 表示数码Q,13 表示数码K;黑桃、红心、梅花、方片分别用1-4 来表示;
小王的表示方法为01,大王的表示方法为02。
输出
输共T 行,每行一个整数,表示打光第T 组手牌的最少次数。

 

solution

真是宇宙无敌大暴搜............(ps:反正我是对着测试点一个一个改过来的........)

不应该是状压:wxh和wq神犇都用状压,反正没改出来

牌型只有三种:1.顺子 2.带牌 3.单牌/对牌  (火箭也算对牌)

1.出牌的顺序不会影响答案

2.先搜顺子可以剪更多的枝,而且搜完顺子后,带牌和 单牌/对牌 可以用贪心求出

思路:

先 暴搜顺子  枚举  单/双/三顺子  左端点  右端点

之后用贪心求 其他牌型  (情况可能会很多.......)

我说说我遇到的坑点:

1.A可以当顺子

2.有不出顺子的出牌方式

3.4个2可以带2个王

4.注意贪心时 判断的优先级

5.4张牌 可以带两个相同的 单/对牌  例如:4个3 带4个2/带对2

这真是一个好题,不能浪费啊..

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<vector>
  5 #define ll long long
  6 #define mem(a,b) memset(a,b,sizeof(a))
  7 using namespace std;
  8 inline int minn(int a,int b){return a<b?a:b;}
  9 
 10 int t,n;
 11 int u,o,bushu;
 12 int a[15];
 13 int limit[4]={0,5,3,2};
 14 
 15 void clear()
 16 {
 17     mem(a,0);
 18 }
 19 
 20 bool check(int l,int size)
 21 {
 22     if(l+limit[size]-1>13)return 0;
 23     for(int i=l+limit[size]-1;i>=l;--i)
 24       if(a[i]<size)return 0;
 25     return 1;
 26 }
 27 
 28 void dfs(int now)
 29 {
 30     for(int size=1;size<=3;++size)
 31         for(int l=2;l<=13;++l)
 32         {
 33             if(!a[l])continue;
 34             if(!check(l,size))continue;
 35             for(int r=l+limit[size]-1;r<=13;++r)
 36             {
 37                 if(a[r]<size)break;
 38                 for(int k=l;k<=r;++k)
 39                   a[k]-=size;
 40                 dfs(now+1);
 41                 for(int k=l;k<=r;++k)
 42                   a[k]+=size;
 43             }
 44         }
 45     
 46     int temp[15];
 47     memcpy(temp,a,sizeof(temp));
 48     
 49     int num1=0,num2=0,num3=0,num4=0;
 50     for(int i=1;i<=13;++i)
 51     {
 52         if(temp[i]==1)++num1;
 53         else if(temp[i]==2)++num2;
 54         else if(temp[i]==3)++num3;
 55         else if(temp[i]==4)++num4;
 56     }
 57     if(num4)
 58       while(num4)
 59       {
 60             if(num1>=2){num1-=2;++now;--num4;continue;}
 61           if(num1==1)
 62           {
 63                 if(num2>=2){num2-=2;--num4;++now;continue;}
 64                 if(temp[14]){--num1;--temp[14];--num4;++now;continue;}
 65                 if(num2){--num2;--num4;++now;continue;}
 66             }
 67             if(num1==0)
 68             {
 69                 if(num2>=2){num2-=2;--num4;++now;continue;}
 70                 if(temp[14]==2){temp[14]=0;--num4;++now;continue;}
 71                 if(temp[14]==1)
 72                     if(num2){--temp[14];--num2;++num1;--num4;++now;continue;}
 73             }
 74             break;
 75         }
 76     if(num3)
 77       while(num3)
 78       {
 79             if(num1){--num1;--num3;++now;continue;}
 80             if(temp[14]){--temp[14];--num3;++now;continue;}
 81             if(num2){--num2;--num3;++now;continue;}
 82             break;
 83         }
 84     
 85     if(temp[14]==2){temp[14]=0;++now;}
 86     int qw=0;
 87     if(num4>=2)
 88         while(num4>=2){num4-=2;++qw;}//4带两个相同的对 
 89     
 90     bushu=minn(now+num1+num2+num3+num4+temp[14]+qw,bushu);
 91 }
 92 
 93 int main(){
 94     scanf("%d%d",&t,&n);
 95     while(t--)
 96     {
 97         clear();
 98         for(int i=1;i<=n;++i)
 99         {
100             scanf("%d%d",&u,&o);
101             if(!u)++a[14];
102             else
103               if(u==1)
104                 ++a[13];
105             else
106               ++a[u-1];
107         }
108         bushu=0x7fffffff;
109         dfs(0);
110         printf("%d\n",bushu);
111     }
112     //while(1);
113     return 0;
114 }
code

 

posted @ 2017-07-30 18:52  A_LEAF  阅读(1071)  评论(0编辑  收藏  举报