题目链接:
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;
}