给你一副麻将,输出这副麻将听什么牌。
T=筒 S=索 W=万
分析:
1.一共只有34种牌,所以可以loop判断是否听这些牌。这样问题就转化为,给你14张牌,判断这副牌能不能胡。
2.递归:首选一个对子,然后每次选3张作为刻子(3个相同)或者顺子。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const char* majiang[] = {
"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 convert(char* s) //只在预处理处调用,因此与速度无关紧要
{
for (int i = 0; i < 34; i++)
if (strcmp(majiang[i], s) == 0)
return i;
return -1;
}
int c[34]; //这里用一个数组来存储34种牌在手上的数量
bool search(int dep) //递归过程 dep=3 因为刻子和顺子加起来=4
{
int i;
for (i = 0; i < 34; i++) //刻子
if(c[i] >= 3)
{
if (dep == 3)
return true;
c[i] -= 3;
if (search(dep + 1))
return true;
c[i] += 3;
}
for (i = 0; i <= 24; i++)
{
if (i % 9 <= 6 && c[i] >= 1 && c[i + 1] >= 1 && c[i + 2] >= 1) //顺子
{
if (dep == 3)
return true;
c[i]--;
c[i + 1]--;
c[i + 2]--;
if (search(dep + 1))
return true;
c[i]++;
c[i + 1]++;
c[i + 2]++;
}
}
return false;
}
bool check()
{
int i = 0;
for (i = 0; i < 34; i++)
if (c[i] >= 2) //对子
{
c[i] -= 2;
if (search(0))
return true;
c[i] += 2;
}
return false;
}
int main()
{
int caseno = 0, i, j;
bool ok;
char s[100];
int mj[15];
while (scanf("%s", &s) == 1)
{
if (s[0] == '0')
break;
printf("Case %d:", ++caseno);
mj[0] = convert(s);
for (i = 1; i < 13; i++)
{
scanf("%s", &s);
mj[i] = convert(s);
}
ok = false;
for (i = 0; i < 34; i++)
{
memset(c, 0, sizeof(c));
for (j = 0; j < 13; j++)
c[mj[j]]++;
if (c[i] >= 4) //每个牌最多拥有4张 等于4张说明不听这张牌
continue;
c[i]++; //假设拥有这张牌
if (check()) //如果“和”了
{
ok = true;
printf(" %s", majiang[i]);
}
c[i]--;
}
if (!ok)
printf(" Not ready");
printf("\n");
}
return 0;
}