zoukankan      html  css  js  c++  java
  • 斗地主

     

    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
  • 相关阅读:
    2019杭电多校训练(一)
    2019牛客多校训练(二)
    2019牛客多校训练(一)
    codeforces#1196F. K-th Path(最短路,思维题)
    codeforces#1108E2. Array and Segments (线段树+扫描线)
    codeforces#1183F. Topforces Strikes Back(数论)
    SPOJ
    2020年4月 第十一届蓝桥杯大赛个人赛(软件类)省级模拟赛
    Codeforces Round #634 (Div. 3)
    POJ
  • 原文地址:https://www.cnblogs.com/leom10/p/11166479.html
Copyright © 2011-2022 走看看