洛谷P2668 斗地主 [NOIP2015]

题目描述

牛牛最近迷上了一种叫斗地主的扑克游戏。斗地主是一种使用黑桃、红心、梅花、方片的A到K加上大小王的共54张牌来进行的扑克牌游戏。在斗地主中,牌的大小关系根据牌的数码表示如下:3<4<5<6<7<8<9<10<J<Q<K<A<2<小王<大王,而花色并不对牌的大小产生影响。每一局游戏中,一副手牌由n张牌组成。游戏者每次可以根据规定的牌型进行出牌,首先打光自己的手牌一方取得游戏的胜利。

现在,牛牛只想知道,对于自己的若干组手牌,分别最少需要多少次出牌可以将它们打光。请你帮他解决这个问题。

需要注意的是,本题中游戏者每次可以出手的牌型与一般的斗地主相似而略有不同。

具体规则如下:

输入输出格式

输入格式:

 

第一行包含用空格隔开的2个正整数Tn,表示手牌的组数以及每组手牌的张数。

接下来T组数据,每组数据n行,每行一个非负整数对aibi表示一张牌,其中ai示牌的数码,bi表示牌的花色,中间用空格隔开。特别的,我们用1来表示数码A,11表示数码J,12表示数码Q,13表示数码K;黑桃、红心、梅花、方片分别用1-4来表示;小王的表示方法为01,大王的表示方法为02。

 

输出格式:

 

共T行,每行一个整数,表示打光第i手牌的最少次数。

 

输入输出样例

输入样例#1:
1 8
7 4
8 4
9 1
10 4
11 1
5 1
1 4
1 1
输出样例#1:
3
输入样例#2:
1 17
12 3
4 3
2 3
5 4
10 2
3 3
12 2
0 1
1 3
10 1
6 2
12 1
11 3
5 2
12 4
2 2
7 2
输出样例#2:
6

说明

样例1说明

共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。

对于不同的测试点, 我们约定手牌组数T与张数n的规模如下:

数据保证:所有的手牌都是随机生成的。

简直可怕的搜索。

  1 /*by SilverN*/
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cstring>
  5 #include<cstdio>
  6 #include<cmath>
  7 using namespace std;
  8 const int mxn=20;
  9 int T;
 10 int n;
 11 int cnt[mxn];
 12 int ans;
 13 int tot=0;
 14 void dfs(int time){
 15     tot++;
 16     if(tot>9000000)return;
 17     if(time>=ans)return;
 18     int i,j;
 19     bool flag=0;
 20     for(i=0;i<=13;i++)
 21         if(cnt[i]){flag=1;break;}
 22     if(!flag){ans=time;return;}
 23     //三顺子
 24     for(i=1;i<=11;i++){
 25         if(cnt[i]<3)continue;
 26         int ed=i;
 27         while(ed<13){
 28             if(cnt[ed]<3)break;
 29             cnt[ed++]-=3;
 30             if(ed-i<2)continue;
 31             dfs(time+1);
 32         }
 33         for(j=i;j<ed;j++)cnt[j]+=3;
 34     }
 35     //双顺子 
 36     for(i=1;i<=10;i++){
 37         if(cnt[i]<2)continue;
 38         int ed=i;
 39         while(ed<13){
 40             if(cnt[ed]<2)break;
 41             cnt[ed++]-=2;
 42             if(ed-i<3)continue;
 43             dfs(time+1);
 44         }
 45         for(j=i;j<ed;j++)cnt[j]+=2;
 46     }
 47     //单顺子
 48     for(i=1;i<=8;i++){
 49         if(!cnt[i])continue;
 50         int ed=i;
 51         while(ed<13){
 52             if(!cnt[ed])break;
 53             cnt[ed++]--;
 54             if(ed-i<5)continue;
 55             dfs(time+1);
 56         }
 57         for(j=i;j<ed;j++)cnt[j]++;
 58     }
 59     //四带
 60     for(i=1;i<=13;i++)
 61         if(cnt[i]>=4){
 62             cnt[i]-=4;
 63             for(j=0;j<=13;j++){
 64               if(i==j)continue;
 65               if(cnt[j]>=2){
 66                   cnt[j]-=2;
 67                   dfs(time+1);
 68                   cnt[j]+=2;
 69               }
 70             }
 71             cnt[i]+=4;
 72         }
 73 
 74     //三带
 75     for(i=1;i<=13;i++)
 76         if(cnt[i]>=3){
 77             cnt[i]-=3;
 78             for(j=0;j<=n;j++)
 79              if(i!=j)
 80              for(int k=1;k<=2;k++){
 81                  if(cnt[j]>=k){
 82                      cnt[j]-=k;
 83                      dfs(time+1);
 84                      cnt[j]+=k;
 85                  }
 86              }
 87             cnt[i]+=3;
 88         }
 89     //火箭 /对子 /炸弹 /单张 
 90     for(j=4;j;j--)
 91         for(i=0;i<=13;i++)
 92             if(cnt[i]>=j){
 93             cnt[i]-=j;
 94             dfs(time+1);
 95             cnt[i]+=j;
 96         }
 97     return;
 98 }
 99 int main(){
100     scanf("%d%d",&T,&n);
101     int i,j;
102     while(T--){
103         memset(cnt,0,sizeof cnt);
104         ans=n;
105         for(i=1;i<=n;i++){
106             int a;
107             scanf("%d%*d",&a);
108             if(a==1)a=12;
109             else if(a==2)a=13;
110             else a-=2;
111             cnt[a]++;
112         }
113         dfs(0);
114         printf("%d
",ans);
115     }
116     return 0;
117 }
View Code

敲了个暴搜果断WAWAWA

然后默默抄了题解

 1 /*by SilverN*/
 2 #include<iostream>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 using namespace std;
 8 const int mxn=30;
 9 int cnt[mxn],r[mxn];
10 int ans;
11 int T,n;
12 int query(){//r存储剩余[i]张的牌的数量
13     int tot=0;
14     memset(r,0,sizeof r);
15     for(int i=0;i<=13;i++)
16         r[cnt[i]]++;
17     while(r[4] && r[2]>=2)r[4]--,r[2]-=2,tot++;
18     while(r[4] && r[1]>=2)r[4]--,r[1]-=2,tot++;
19     while(r[4] && r[2])r[4]--,r[2]--,tot++;
20     while(r[3] && r[2])r[3]--,r[2]--,tot++;
21     while(r[3] && r[1])r[3]--,r[1]--,tot++;
22     return tot+r[1]+r[2]+r[3]+r[4];
23 }
24 void dfs(int time){
25     if(time>=ans) return;
26     int tmp=query();
27     if(time+tmp<ans)ans=tmp+time;
28     int i,j,x;
29     for(i=3;i;i--)
30         for(j=2;j<=13;j++){
31             x=j;
32             while(cnt[x]>=i){
33                 x++;
34                 if((i==3 && x-j>=2)||(i==2 && x-j>=3)||(i==1 && x-j>=5)){
35                     for(int k=j;k<x;k++) cnt[k]-=i;
36                     dfs(time+1);
37                     for(int k=j;k<x;k++) cnt[k]+=i;
38                 }
39             }
40         }
41 }
42 int main(){
43     scanf("%d%d",&T,&n);
44     int i,j;
45     while(T--){
46         memset(cnt,0,sizeof cnt);
47         ans=n;
48         for(i=1;i<=n;i++){
49             int a;
50             scanf("%d%*d",&a);
51             if(a==1)a=13;
52             else if(a)a--;
53             cnt[a]++;
54         }
55         dfs(0);
56         printf("%d
",ans);
57     }
58     return 0;
59 }
原文地址:https://www.cnblogs.com/SilverNebula/p/5778298.html