洛谷P2668 斗地主

传送门

注意模拟的先后顺序

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#define re register
using namespace std ;

inline int read () {
    int f = 1 , x = 0 ;
    char ch = getchar () ;
    while(ch < '0' || ch > '9')  {if(ch == '-')  f = -1 ; ch = getchar () ;}
    while(ch >= '0' && ch <= '9')  {x = (x << 1) + (x << 3) + ch - '0' ; ch = getchar () ;}
    return x * f ;
}

int card[16] ;
int n , m , ans ;

bool check() {
    for(re int i = 1 ; i <= 14 ; ++ i) 
        if(card[i])  return false ;
    return true ;
}

inline void dfs(int h) {
    if(h > ans) {return ;}
    if(check()) { ans = min(ans , h) ; }
    int s1 = 0 , s2 = 0 , s3 = 0 , s4 = 0 ;
    //s1:统计单牌 , s2:统计对子 
    for(re int i = 1 ; i <= 14 ; ++ i) {
        if(card[i] == 1)  s1 ++ ;
        if(card[i] == 2)  s2 ++ ;
    }
    //s4:统计四个的牌 
    //四带二的代码 
    for(re int i = 1 ; i <= 13 ; ++ i) {
        if(card[i] == 4) {
            s4 ++ ;
            if(s1 >= 2)  s1 -= 2 ; //四带二(带两个单牌) 
            else if(s2 >= 2)  s2 -= 2 ; //四带二(带两个对子) 
            else if(s2 >= 1)  s2 -- ; //四带二(带一个对子也就是两个相同的单牌) 
        }
    }
    //s3:统计三个的牌 
    for(re int i = 1 ; i <= 13 ; ++ i) {
        if(card[i] == 3) {
            s3 ++ ;
            if(s1 >= 1)  s1 -= 1 ; //三带一 
            else if(s2 >= 1)  s2 -= 1 ; //三带一对 
        }
    }
    //ans:没有顺子情况下最小的排量 
    ans = min(ans , h + s1 + s2 + s3 + s4) ;
    //是否有顺子 
    for(re int i = 1 ; i <= 8 ; ++ i) {
        int j ;
        for(j = i ; j <= 12 ; ++ j) {
            card[j] -- ;
            if(card[j] < 0)  break ;
            if(j - i + 1 >= 5)  
                dfs(h + 1) ;
        }
        if(j == 13)  j -- ;
        while(j >= i)  card[j--]++ ;
    }
    for(re int i = 1 ; i <= 10 ; ++ i) {
        int j ;
        for(j = i ; j <= 12 ; ++ j) {
            card[j] -= 2 ;
            if(card[j] < 0)  break ;
            if(j - i + 1 >= 3)  
                dfs(h + 1) ;
        }
        if(j == 13)  j -- ;
        while(j >= i)  card[j--] += 2 ;
    }
    for(re int i = 1 ; i <= 11 ; ++ i) {
        int j ;
        for(j = i ; j <= 12 ; ++ j) {
            card[j] -= 3 ;
            if(card[j] < 0)  break ;
            if(j - i + 1 >= 2)
                dfs(h + 1) ;
        }
        if(j == 13)  j -- ;
        while(j >= i)  card[j--] += 3 ;
    }
}

int main () {
    n = read () ; m = read () ;
    while(n > 0) {
        memset(card , 0 , sizeof(card)) ;
        for(re int i = 1 ; i <= m ; ++ i) {
            int x , y ;
            x = read () ; y = read () ;
            if(x == 1 || x == 2) {
                card[11 + x] ++ ;
                continue; 
            }
            if(x == 0) {
                card[14] ++ ;
                continue ;
            }
            card[x - 2] ++ ;
        }
        ans = 24 ;
        dfs(0) ;
        printf("%d" , ans) ;
        if(n != 1)  cout << endl ;
        n-- ;
    }
    return 0 ;
}

转载于:https://www.cnblogs.com/Stephen-F/p/10618179.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值