斗地主

 

4325:斗地主

Time Limit: 30 Sec  Memory Limit: 1024 MB
Submit: 270  Solved: 192
[Submit][Status][Discuss]

 

Description

 

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

 

Input

 

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

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

 

Output

 

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

 

Sample Input

 

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

 

Sample Output

 

3

 

HINT

 

 共有1组手牌,包含8张牌:方片7,方片8,黑桃9,方片10,黑桃J,黑桃5,方


片A以及黑桃A。可以通过打单顺子(方片7,方片8,黑桃9,方片10,黑桃J),单张

牌(黑桃5)以及对子牌(黑桃A以及方片A)在3次内打光。

 

T<=10

N<=23

 

这题看题面,很容易想到爆搜方法(然而我一开始还是想错了~~亿万只羊驼奔过),就是按他题中所说的出法,一个一个枚举,不停地枚举顺子,三带,四带,但这是非常nc的,所枚举状态之多不可想象。

所以就要枚举出牌数,这样你dfs的参量就是ans,并且更新十分方便。但需要注意的是一定不能枚举单牌,搜索复杂度很大,但是并没有什么卵用,因为你搜完了那些比较高级的出牌方式后之后,必定剩下的,就是带不走的了,所以for循环一遍统计答案即可(北岸大神骚操作),一开始我很脑残的搜单牌,于是t30,惨的一批;

代码如下:

for(int i=2;i<=15;i++) if(card[i]) now++;

ans=min(now,ans);

然后就是要处理高级的出法(顺子和带牌)

首先是带牌,思路很简单,以三带一为例。

就是搜到有三个以上牌的就再展开一层循环,枚举其他牌只要有符合条件的就接着搜出牌数++(其实就是往下搜,即dfs(now+1))。

代码如下(仅以三带一为例,其他带牌同理):

for(int i=2;i<=14;i++){

if(card[i]>=3){

card[i]-=3;

for(int j=2;j<=15;j++){

if(j==i)continue;

if(card[j]){

card[j]--;

dfs(now+1);

card[j]++;

}

}

card[i]+=3;

}

}

最后是顺子,很多人不知道怎么处理顺子,但我莫名的一看到顺子就想到一调考试T3旅馆的暴力打法,因为他都是对于一个对长度有要求的并且连续的区间进行处理,处理方法即为用一个变量记录顺子长度,满足条件就接着搜,不满足条件就把记录长度的变量赋为0(相当于从新开始),搜下一层,处理方法十分简单。

代码如下(特别注意:循环不能从2开始,一开始我因为这个一直WA35):

int len=0;

for(int i=3;i<=14;i++){//单顺

if(!card[i]) len=0;

if(card[i]){

len++;

if(len>=5){

for(int j=i;j>=i-len+1;j--) card[j]--;

dfs(now+1);

for(int j=i;j>=i-len+1;j--) card[j]++;

}

}

}

最后要说的是一个预处理的小技巧:

因为A 2 3 4 5并不能组成顺子,但10 J Q K A却能,所以把存A的数组下标置为14,这样就方便很多。

最后是学到的关于循环的知识(蛤?):

for(int j=2;j<=15&&j!=i;j++) 这种打法如果i==j会break;

但是这题你需要continue;

所以我们需要这种骚代码(此处感谢烫胸Smily一万次):

for(int j=2;j<=15;j++){

if(j==i)continue;

最后,最最重要的一点:

数组不清空,爆零两行泪!!!

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 int T,n;
  8 int card[20];
  9 int ans=27;
 10 inline bool check(){
 11     int ju=0;
 12     for(int i=2;i<=14;i++){
 13         if(card[i]) ju=1;
 14     }
 15     return ju;
 16 }
 17 inline void dfs(int now){//按出牌数搜 
 18     if(now>=ans) return;
 19 //    if(!check()) ans=min(now,ans);
 20     int len=0;
 21     for(int i=3;i<=14;i++){//单顺 
 22         if(!card[i]) len=0;
 23         if(card[i]){
 24             len++;
 25             if(len>=5){
 26                 for(int j=i;j>=i-len+1;j--) card[j]--;
 27                 dfs(now+1);
 28                 for(int j=i;j>=i-len+1;j--) card[j]++;
 29             }
 30         }
 31         
 32     }
 33 //    if(!check()) ans=min(now,ans);
 34     int lens=0;
 35     for(int i=3;i<=14;i++){//双顺 
 36         if(card[i]<2) lens=0;
 37         if(card[i]>=2){
 38             lens++;
 39             if(lens>=3){
 40                 for(int j=i;j>=i-lens+1;j--) card[j]-=2;
 41                 dfs(now+1);
 42                 for(int j=i;j>=i-lens+1;j--) card[j]+=2;
 43             }
 44         }
 45     }
 46 //    if(!check()) ans=min(now,ans);
 47     int lenc=0;
 48     for(int i=3;i<=14;i++){//三顺
 49         if(card[i]<3) lenc=0;
 50         if(card[i]>=3){
 51             lenc++;
 52             if(lenc>=2){
 53                 for(int j=i;j>=i-lenc+1;j--) card[j]-=3;
 54                 dfs(now+1);
 55                 for(int j=i;j>=i-lenc+1;j--) card[j]+=3;
 56             }
 57         }
 58     }
 59 //    if(!check()) ans=min(now,ans);
 60     for(int i=2;i<=14;i++){
 61         if(card[i]>=3){
 62             card[i]-=3;
 63             for(int j=2;j<=15;j++){
 64                 if(j==i)continue; 
 65                 if(card[j]){
 66                     card[j]--;
 67                     dfs(now+1);
 68                     card[j]++;
 69                 }
 70             }
 71             card[i]+=3;
 72         }
 73     }
 74 //    if(!check()) ans=min(now,ans);
 75     for(int i=2;i<=14;i++){
 76         if(card[i]>=3){
 77             card[i]-=3;
 78             for(int j=2;j<=15;j++){
 79                 if(j==i) continue;
 80                 if(card[j]>=2){
 81                     card[j]-=2;
 82                     dfs(now+1);
 83                     card[j]+=2;
 84                 }
 85             }
 86             card[i]+=3;
 87         }
 88     }
 89 //    if(!check()) ans=min(now,ans);
 90     for(int i=2;i<=14;i++){
 91         if(card[i]==4){
 92             card[i]-=4;
 93             for(int j=2;j<=15;j++){
 94                 if(j==i)continue;
 95                 if(card[j]){
 96                     card[j]--;
 97                     for(int k=2;k<=15;k++){
 98                         if(k==j||k==i)continue;
 99                         if(card[k]){
100                             card[k]--;
101                             dfs(now+1);
102                             card[k]++;
103                         }
104                     }
105                     card[j]++;
106                 }
107             }
108             card[i]+=4;
109         }
110     }
111 //    if(!check()) ans=min(now,ans);
112     for(int i=2;i<=14;i++){
113         if(card[i]==4){
114             card[i]-=4;
115             for(int j=2;j<=15;j++){
116                 if(j==i) continue;
117                 if(card[j]>=2){
118                     card[j]-=2;
119                     for(int k=2;k<=15;k++){
120                         if(k==i||k==j)continue;
121                         if(card[k]>=2){
122                             card[k]-=2;
123                             dfs(now+1);
124                             card[k]+=2;
125                         }
126                     }
127                     card[j]+=2;
128                 }
129             }
130             card[i]+=4;
131         }
132     }
133     for(int i=2;i<=15;i++) if(card[i]) now++;
134     ans=min(now,ans);
135 }
136 int main(){
137     scanf("%d%d",&T,&n);
138     while(T--){
139         ans=0x7f;
140         memset(card,0,sizeof(card));
141         for(int i=1;i<=n;i++){
142             int a,b;
143             scanf("%d%d",&a,&b);
144             if(a==0) a+=15;
145             if(a==1) a+=13;
146             card[a]++;
147         }
148         dfs(0);
149         printf("%d
",ans);
150     }
151 }
View Code
原文地址:https://www.cnblogs.com/leom10/p/11166479.html