hihocoder #1503 : 一人麻将

37 篇文章 0 订阅
19 篇文章 0 订阅

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB

描述

小Hi在北方的暖气里温暖如春,小Ho却在南方的艳阳里感受大雪纷飞。距离使得他们连一起打麻将的机会都没有,失落的小Hi一个人玩起了麻将。

小Hi玩的是四川麻将,因此只有3种序数牌万、筒、条,每种花色一到九各4张。

小Hi起手拥有14张牌,之后小Hi每摸一张牌后,如果没有胡牌,就出一张牌,直至胡牌或牌被摸光。反正一个人玩又赢不到小Ho的钱,因此小Hi永远也不会选择暗杠。

胡牌的规则如下:

手中14张牌最多只能属于两个花色。

手中14张牌的牌型须满足下列两个条件之一:

1)3 + 3 + 3 + 3 + 2,其中的3代表一坎(指同花色且同数字、或同花色且数字相连的三张牌),其中的2代表一个对子(指两张同花色且同数字的牌)。

2)2 × 7,即14张牌构成7个对子,特别的,四张花色数字全相同的牌可以看作两个对子。
万、筒、条分别记为a, b, c,以下对能胡牌的牌型举出一些例子:

a1 a2 a3 a5 a5 a5 c3 c4 c5 c5 c6 c7 c7 c7

b2 b2 b5 b5 b7 b7 b8 b8 c1 c1 c2 c2 c3 c3

现给出小Hi的起手牌,并按顺序给出场上其余小Hi将要摸的牌。(小Hi只拿出了一副麻将的一部分牌玩,因此并不是每张牌都会被摸到。)

请计算小Hi最早在摸第几张牌之后就可能胡牌,天胡(起手牌构成胡牌牌型)记为第0张。无法胡牌输出-1。

输入

每张牌用a, b或c其后紧接一个数字1-9表示。

第一行是一个正整数n (n <= 94),代表将要摸的牌。

第二行是14张手牌。

第三行是n张底牌,按摸牌顺序给出。

输出

输出一个整数,代表最早在摸第几张牌之后可能胡牌,无法胡牌输出-1。

样例输入
12
a1 a1 a1 a2 a3 a4 a5 a6 a7 a8 a9 a9 a9 c1
c2 b1 b2 b4 b5 c1 b7 b8 a1 a2 a3 a4
样例输出
6

..

不敢搜啊,其实算算搜索深度只有4层,还是可以无脑搜的

每一层节点得选取无非是 123连着的 或者三个重复的

到达第四层后 看看是否有对子即可

特判一下七小对


参考网上代码的实现:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int size = 255;



int cnt[3][10];
int k1,k2;
bool ok1_sub(int dep)
{
    if (dep>4)
    {
        for(int i=1;i<=9;i++)
            if (cnt[k1][i]>=2) return true;
        for(int i=1;i<=9;i++)
            if (cnt[k2][i]>=2) return true;
        return false;
    }
    for(int i=1;i<=9;i++)
    {
        if (cnt[k1][i]>=3)
        {
            cnt[k1][i]-=3;
            if (ok1_sub(dep+1)) return true;
            cnt[k1][i]+=3;
        }
    }
    for(int i=1;i<=9;i++)
    {
        if (cnt[k2][i]>=3)
        {
            cnt[k2][i]-=3;
            if (ok1_sub(dep+1)) return true;
            cnt[k2][i]+=3;
        }
    }
    for(int i=1;i<=7;i++)
    {
        if (cnt[k1][i]&&cnt[k1][i+1]&&cnt[k1][i+2])
        {
            cnt[k1][i]--,cnt[k1][i+1]--,cnt[k1][i+2]--;
            if (ok1_sub(dep+1)) return true;
            cnt[k1][i]++,cnt[k1][i+1]++,cnt[k1][i+2]++;
        }
    }
    for(int i=1;i<=7;i++)
    {
        if (cnt[k2][i]&&cnt[k2][i+1]&&cnt[k2][i+2])
        {
            cnt[k2][i]--,cnt[k2][i+1]--,cnt[k2][i+2]--;
            if (ok1_sub(dep+1)) return true;
            cnt[k2][i]++,cnt[k2][i+1]++,cnt[k2][i+2]++;
        }
    }
return false;
}
bool ok1()
{
    for(k1=0;k1<=2;k1++)
        for( k2=k1;k2<=2;k2++)
            if (ok1_sub(1)) return true;
            return false;
}
bool ok2()
{
    int num[3];
    for(int i=0;i<=2;i++)
    {
        num[i]=0;
        for(int j=1;j<=9;j++)num[i]+=cnt[i][j]/2;
    }
    if (num[0]+num[1]>=7)return true;
    if (num[2]+num[1]>=7)return true;
    if (num[2]+num[0]>=7)return true;
        return false;
}
int main()
{
    int n;
    cin>>n;
    char ss[4];
    for(int i=1; i<=14; i++)
    {
        scanf("%s",ss);
        cnt[ ss[0]-'a'  ][ss[1]-'0']++;
    }
    if (ok1()||ok2())
    {
        return  printf("0\n") ,0;
    }
    for(int i=1; i<=n; i++)
    {
        scanf("%s",ss);
        cnt[ ss[0]-'a'  ][ss[1]-'0']++;
        if (ok1()||ok2())
            return  printf("%d\n",i) ,0;
    }
  return   printf("-1\n"),0;



    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值