【ICPC2021昆明】mahjong

题目链接:

https://ac.nowcoder.com/acm/contest/14055/I

题目大意:

麻将规则略。给你14张麻将,问是否已经听牌,若已经听了则输出Tsumo!,反之则说出有几种打法可以听牌,并输出对应的打法以及胡哪些牌。

解题思路:

这其实是小贪心+模拟题,重要的是模拟。麻将四种花色,将对应花色用数字储存表示。先判断没有两个牌能不能胡,再加上两个牌能不能胡。

重点:

模拟题重要的是理清思路进行模拟,更多的是考细节和模拟过程,耐心地做就好。

代码实现:

#include <bits/stdc++.h> //code by cjj490168650
using namespace std;

int T;
char s[110];
int cnt[50],tmp[50],sum[10];

int getnum(char x,char y)
{
    int re=x-'0';
    if (y=='b') re+=10;
    if (y=='s') re+=20;
    if (y=='z') re+=30;
    return re;
}
char get_char(int id)
{
    if (id<10) return 'w';
    if (id<20) return 'b';
    if (id<30) return 's';
    return 'z';
}
bool pre_hu(int *cnt){
    for(int i=1;i<=29;i++){
        if(cnt[i]%3){
            if(cnt[i+1]<cnt[i]%3) 
				return false;
            if(cnt[i+2]<cnt[i]%3) 
				return false;
            cnt[i+1]-=cnt[i]%3;
            cnt[i+2]-=cnt[i]%3;
        }
    }
    for(int i=31;i<=37;i++)
        if(cnt[i]%3) 
			return false;
    return true;
}

bool can_hu(){
    bool f=false;
    for(int i=1;i<=37;i++){
        if(cnt[i]>=2){
            cnt[i]-=2;
            memcpy(tmp,cnt,sizeof(cnt));
            if (pre_hu(tmp)) f=true;
            cnt[i]+=2;
            if (f) return true;
        }
    }
    return false;
}

void work(){
	scanf("%s",s+1);
    memset(cnt,0,sizeof(cnt));
    memset(sum,0,sizeof(sum));
    for (int i=1;i<=28;i+=2){
        int id=getnum(s[i],s[i+1]);
        cnt[id]++;
        sum[id/10]++;
    }
    if(can_hu()) printf("Tsumo!\n");
    else{
        map<int,vector<int>> ans;
        for(int i=1;i<=37;i++){
            if (!cnt[i]) continue;
            cnt[i]--;
            sum[i/10]--;
            for(int j=1;j<=37;j++){
                if (j%10==0) continue;
                cnt[j]++;
                sum[j/10]++;
                if (can_hu())
                    ans[i].push_back(j);
                cnt[j]--;
                sum[j/10]--;
            }
            cnt[i]++;
            sum[i/10]++;
        }
        printf("%d\n",(int)ans.size());
        for(auto [i,v]:ans){
            printf("%d%c ",i%10,get_char(i));
            for(int j:v)
                printf("%d%c",j%10,get_char(j));
            printf("\n");
        }
    }
}
int main()
{
    scanf("%d",&T);
    while (T--){
        work();
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值