[NOIP2015] 斗地主

NOIP2015 斗地主

时间限制: 3 Sec  内存限制: 1024 MB

题目描述

 牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的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组手牌的最少次数。

样例输入

1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1

样例输出

3

solution

一道大暴搜

    开始的时候没有想到应该按照什么样的顺序搜,弄得很没有头绪

   正解是想找长的搜,我是先找的各种顺子,然后是四个及带的,然后是三个及带的;最后是单牌,在搜的时候,要保证枚举到了各种情况,这样才能保证找到了最优解,所以用到了memcpy,枚举到了一种情况就继续搜索,在最后有一个极大的剪枝,当在排除掉所有枚举单牌的情况下,可以把剩下的手牌全部按相同的分次出掉,因为如果还有顺子之类的东西,在前面会枚举到,而且在最后扔的情况也不是最优解,这样就能省掉前面一段繁琐的枚举,能快很多;可以把2的编号与其他的隔开,这样无论如何也成不了顺子,省了很多事;

感悟

1、暴力搜索越早判断越好

2、在搜的时候找准一种顺序全部枚举,可以先不考虑时间问题,可以在最后在集中想剪枝;

3、memcpy超级有用,小数组都可以这么搞;

  1 #include<cmath>
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8 using namespace std;
  9 int T,n,N,ans,lim;
 10 void find(int a[20],int num,int sum){
 11     if(num>ans) return ;
 12     if(sum==n){
 13         ans=num-1;
 14         return ;
 15     }
 16     int b[20],ji=1;
 17     if(n-sum>=6){
 18         for(int i=1;i<=lim;i++){
 19             if(a[i]<3){
 20                 ji=i+1; continue;
 21             }
 22             if(i-ji+1>=2){
 23                 memcpy(b,a,sizeof(b));
 24                 for(int j=ji;j<=i;j++){
 25                     b[j]-=3;
 26                 }
 27                 find(b,num+1,sum+3*(i-ji+1));
 28             }
 29         }
 30         ji=1;
 31         for(int i=1;i<=lim;i++){
 32             if(a[i]<2){
 33                 ji=i+1; continue;       
 34             }
 35             if(i-ji+1>=3){
 36                 memcpy(b,a,sizeof(b));
 37                 for(int j=ji;j<=i;j++){
 38                     b[j]-=2;
 39                 }
 40                 find(b,num+1,sum+2*(i-ji+1));
 41             }
 42         }
 43     }
 44     if(n-sum>=5){
 45         ji=1;
 46         for(int i=1;i<=lim;i++){
 47             if(a[i]<1){
 48                 ji=i+1; continue;   
 49             }
 50             if(i-ji+1>=5){
 51                 memcpy(b,a,sizeof(b));
 52                 for(int j=ji;j<=i;j++){
 53                     b[j]--;
 54                 }
 55                 find(b,num+1,sum+(i-ji+1));
 56             }
 57         }
 58     }
 59     int c[20];
 60     if(n-sum>=4){
 61         for(int i=1;i<=lim;i++){
 62             if(a[i]==4){
 63                 memcpy(b,a,sizeof(b));
 64                 b[i]-=4;
 65                 find(b,num+1,sum+4);
 66                 memcpy(b,a,sizeof(b));
 67                 b[i]-=4;
 68                 int mk, he=0;
 69                 if(n-sum-4>=4){
 70                     for(int j=1;j<=N;j++){
 71                         if(b[j]>=2){
 72                             if(b[j]==4){
 73                                 memcpy(c,b,sizeof(c));
 74                                 c[j]-=4;
 75                                 find(c,num+1,sum+8);
 76                             }
 77                             for(int k=j+1;k<=N;k++){
 78                                 if(b[k]>=2){
 79                                     memcpy(c,b,sizeof(c));
 80                                     c[j]-=2; c[k]-=2;
 81                                     find(c,num+1,sum+8);
 82                                 }
 83                             }
 84                         }
 85                     }
 86                 }
 87                 if(n-sum-2>=2){
 88                     for(int j=1;j<=N;j++){
 89                         if(b[j]>=1){
 90                             if(b[j]==2){
 91                                 memcpy(c,b,sizeof(c));
 92                                 c[j]-=2;
 93                                 find(c,num+1,sum+6);
 94                             }
 95                             for(int k=j+1;k<=N;k++){
 96                                 if(b[k]>=1){
 97                                     memcpy(c,b,sizeof(c));
 98                                     c[j]--; c[k]--;
 99                                     find(c,num+1,sum+6);
100                                 }
101                             }
102                         }
103                     }
104                 }
105                  
106             }
107         }
108     }
109     if(n-sum>=3){
110         for(int i=1;i<=lim;i++){
111             if(a[i]>=3){
112                 memcpy(b,a,sizeof(b));
113                 b[i]-=3;
114                 find(b,num+1,sum+3);
115                 memcpy(b,a,sizeof(b));
116                 b[i]-=3;
117                 if(n-sum-3>=2){
118                     for(int j=1;j<=N;j++){
119                         if(b[j]>=2){
120                             memcpy(c,b,sizeof(c));
121                             c[j]-=2;
122                             find(c,num+1,sum+5);
123                         }
124                     }
125                 }
126                 if(n-sum-3>=1){
127                     for(int j=1;j<=N;j++){
128                         if(b[j]>=1){
129                             memcpy(c,b,sizeof(c));
130                             c[j]--;
131                             find(c,num+1,sum+4);
132                         }
133                     }
134                 }
135             }
136         }
137     }
138     int he=num-1;
139     for(int i=1;i<=lim;i++){
140         if(a[i]) he++; 
141         if(he>=ans) return ;
142     }
143     ans=min(ans,he);
144 }
145 int main(){
146     //freopen("a.in","r",stdin);
147     //freopen("landlords.in","r",stdin);
148     //freopen("landlords.out","w",stdout);
149     scanf("%d%d",&T,&n);
150     int a[20];
151     N=14; lim=18;
152     while(T--){
153         memset(a,0,sizeof(a));
154         int x,y;
155         for(int i=1;i<=n;i++){
156             scanf("%d%d",&x,&y);
157             if(x==1) a[14]++;
158             else if( x==2 ) a[16]++;
159             else if(x==0 && y==1) a[17]++;
160             else if(x==0 && y==2) a[17]++;
161             else a[x]++;
162         }
163         ans=0x7fffffff;
164         find(a,1,0);
165         printf("%d
",ans);
166     }
167     return 0;
168 }
 
原文地址:https://www.cnblogs.com/FOXYY/p/7265713.html