分析:
身为一个麻将老手,我都不一定能”听“全牌
一共只有34种牌,我们可以考虑枚举每一张牌,
这样问题就可以转化成判断14张牌是否可以“和”
为此,我们可以枚举将牌,之后每次选三张作为刻子或者顺子
如图:选将有5种方式
为了快速的选出将,顺,刻,我们可以用一个34维向量表示每一张牌有多少,
除了第一次枚举将牌,我们每次只用考虑最小的牌在哪一个顺子或刻子里就好了
tip
每种牌只有4张
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const char *mahjong[]={"1T","2T","3T","4T","5T","6T","7T","8T","9T","1S",
"2S","3S","4S","5S","6S","7S","8S","9S","1W","2W",
"3W","4W","5W","6W","7W","8W","9W","DONG","NAN","XI",
"BEI","ZHONG","FA","BAI"};
int mj[15],c[40];
int cl(char *s)
{
for (int i=0;i<34;i++)
if (strcmp(mahjong[i],s)==0) return i;
return -1;
}
int solve(int num) //当前已经有的3元组
{
int i;
for (i=0;i<34;i++) //刻子
if (c[i]>=3)
{
if (num==4) return 1;
c[i]-=3;
if (solve(num+1)) return 1;
c[i]+=3;
}
for (i=0;i<27;i++) //顺子
if (i%9<=6&&c[i+1]>=1&&c[i+2]>=1&&c[i]>=1) //没有以8,9开头的顺子
{
if (num==4) return 1;
c[i]--; c[i+1]--; c[i+2]--;
if (solve(num+1)) return 1;
c[i]++; c[i+1]++; c[i+2]++;
}
return 0;
}
int check()
{
for (int i=0;i<34;i++) //每种牌都可以作为将
{
if (c[i]<2) continue;
c[i]-=2;
if (solve(1)) return 1;
c[i]+=2;
}
return 0;
}
int main()
{
int cas=0;
char s[10];
while (scanf("%s",&s)==1)
{
if (s[0]=='0') break;
printf("Case %d:",++cas);
mj[0]=cl(s);
for (int i=1;i<13;i++)
{
scanf("%s",&s);
mj[i]=cl(s);
}
bool ff=0;
for (int i=0;i<34;i++)
{
memset(c,0,sizeof(c));
for (int j=0;j<13;j++) c[mj[j]]++;
if (c[i]==4) continue;
c[i]++;
if (check())
{
ff=1;
printf(" %s",mahjong[i]);
}
c[i]--;
}
if (!ff) printf(" Not ready");
printf("
");
}
return 0;
}