「2019计蒜之道复赛 B」个性化评测系统

题目描述

“因材施教”的教育方式自古有之,互联网时代,要实现真正意义上的个性化教育,离不开大数据技术的扶持。VIPKID 英语 20 多万学员每月在课前预习、课中教学、课后复习、作业、答题测评等环节会产生超过 100 TB 的数据增量,在对庞大数据进行分析之后,个性化评测系统会自动生成针对每个学生的量化学习报告和个性化学习图谱。

正在拿着自己的个性化学习图谱总结分析的 Dino,看到走来的小明手中拿的麻将牌,心生一题,给小明出了一道难题:“你知道怎么输出听牌吗?”看到复杂的规则,小明皱起了眉毛,请你一起来帮小明解决吧!请看题:

在麻将游戏中,有 34 种牌,分别是 1-9 的万,1-9 的筒,1-9 的条,以及 7 种字牌 “东”,“南”,“西”,“北”,“白”,“发”,“中”。

这 34 种牌各四张,共 136 张。

如果你手牌中凑够了 14 张牌,满足一定的牌型条件,就称作“和牌”。

这个牌型有很多种,但在本题中,只考虑最基本的一种,4 个面子 + 1 个雀头组成的牌型。

面子是刻子和顺子的统称,雀头是对子。

刻子指的是,三张一样的牌。

顺子指的是,三张连续的牌,注意,只有非字牌(也就是万,筒,条)才能连续,例如一二三万,四五六筒,并且不能循环连续,比如九一二条就不算顺子。

对子指的是,两张一样的牌。

现在,zcy 手中有 13 张牌,并且再得到某一张牌,就可以和牌,而你的目标就是输出能使 zcy 和牌的牌。

注意一种特殊情况,如果你手牌中某张牌有四张,而再得到这张牌也能和牌,这张牌在本题中不需要输出,因为这张牌总共就只有四张,不可能拿到手了。

(如果你知道什么是杠,请假装不能杠,如果你不知道,那就不需要知道了。)

输入格式

1-9万用对应数字 + 一个小写 m 表示

​1-9条用对应数字 + 一个小写 s 表示

​1-9筒用对应数字 + 一个小写 p 表示

​东南西北白发中分别用 1-7 的数字 + 一个小写 z 表示

​输入多组数据,每组共 13 个数字 + 字母的组合,用空格隔开

​输入保证有解

输出格式

对于每组数据,输出若干行,每行一个听牌,按照万,条,筒,字的顺序输出听牌,同类型按照数从小到大输出

数据组数不超过 10 组

样例输入

1s 2s 3s 4s 5s 6s 7s 8s 9s 1z 1z 3p 4p

样例输出 复制

2p
5p

题解:

  • 先暴力枚举对子,再暴力枚举刻子,check剩下的是不是能组成剩余的顺子就行了

代码:

#include<bits/stdc++.h>

using namespace std;

char s[100][3];
int cnt[5][10],cur[5][10];

char trans(int k)
{
    if(k==1) return 'm';
    else if(k==2) return 's';
    else if(k==3) return 'p';
    else return 'z';
}

int get(char k)
{
    if(k=='m') return 1;
    else if(k=='s') return 2;
    else if(k=='p') return 3;
    else return 4;  
}

int tot[]={0,9,9,9,7};
int kezi[100][2],ke=0,tmp[5][10];
bool ch[100];

bool dfs(int curr,int tot1,int want)
{
    if(curr==ke+1){
        if(tot1==want){
            for(int i=1;i<=4;i++) for(int j=1;j<=tot[i];j++) tmp[i][j]=cur[i][j];
            for(int i=1;i<=ke;i++) if(ch[i]) tmp[kezi[i][0]][kezi[i][1]]-=3;

            int res=0;
            for(int i=1;i<=4;i++) for(int j=1;j<=tot[i];j++){
                while(tmp[i][j]){
                    if(i==4||j>7) return false;
                    if(!tmp[i][j+1]||!tmp[i][j+2]) return false;
                    tmp[i][j+1]--;tmp[i][j+2]--;tmp[i][j]--;
                    res++;
                }
            }
            return res+want==4;
        }
        return false;
    }
    if(tot1>want) return false;
    ch[curr]=true;
    if(dfs(curr+1,tot1+1,want)) return true;
    ch[curr]=false;
    if(dfs(curr+1,tot1,want)) return true;
    return false;
}

bool check(int a,int b)
{
    memset(cur,0,sizeof(cur));
    for(int i=1;i<=4;i++) for(int j=1;j<=tot[i];j++) cur[i][j]=cnt[i][j];cur[a][b]++;
    for(int i=1;i<=4;i++){
        for(int j=1;j<=tot[i];j++){
            if(cur[i][j]>=2){
                cur[i][j]-=2;
                ke=0;
                for(int k=1;k<=4;k++){
                    for(int l=1;l<=tot[k];l++){
                        if(cur[k][l]>=3){
                            kezi[++ke][0]=k;
                            kezi[ke][1]=l;
                        }
                    }
                }
                for(int k=0;k<=min(4,ke);k++){ //刻子数量
                    memset(ch,0,sizeof(ch));
                    if(dfs(1,0,k)) return true;
                }


                cur[i][j]+=2;
            }
        }
    }
    return false;
}


int main()
{
    while(~scanf("%s",s[1]+1)){
        memset(cnt,0,sizeof(cnt));
        for(int i=2;i<=13;i++) scanf("%s",s[i]+1);
        for(int i=1;i<=13;i++){
            int type=get(s[i][2]);
            cnt[type][s[i][1]-'0']++;
        }
        for(int i=1;i<=4;i++){
            for(int j=1;j<=tot[i];j++){
                if(cnt[i][j]<=3&&check(i,j)){
                    printf("%d%c\n",j,trans(i));
                }
            }
        }

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值