题目链接:点击这里
解题思路
对于不懂麻将的我来说,此题花了不少时间去揣摩题意。不过其实题目简化了规则:手上有13张牌,要摸一张胡牌,叫你求摸哪一张可以胡牌。由于整副牌只能拆成一个将(两张相同的牌),不限数量个刻子或顺子。因此,我们可以想象,任意摸一张牌后,除去将,还有12张牌,正好分为4组(3张为一组)刻子或顺子。
因此,此题首先应该是遍历所有可能摸到的牌,然后检查当前牌是否可能胡牌。检查的方式应该为先找将(有两张以上的牌都可能),然后递归找顺子和刻子。
技巧及注意事项
- 此题思路比较容易,但第一步是要把所有的字符串转换为便于处理和表达的字符。因此本文直接将其转换为了ID。
- 寻找顺子时,从顺子的最小值开始取,因此最大顺子为7W8W9W,并且注意在连续的T和S和W之间是不能形成顺子的。
- 回溯法要注意每次进行递归尝试后,要将减去的数量重新加上。
- 注意在主函数中,若找到和牌,number中的数量会变为0,因此需要额外数组进行还原。
- 在添加第14张牌时,若手牌种相同的牌已经有4张,则不可能再添加。
代码示例:
#include <iostream>
#include <string>
#include <string.h>
using namespace std;
const string 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 convert(string name)
{
for (int i = 0; i < 34; i++)
{
if (mahjong[i] == name) return i;
}
return -1;
}
int number[34],origin[34];
bool recursive(int dep)
{
int i;
for (i = 0; i < 34; i++)
{
if (number[i] >= 3)
{
//可以为刻子,三张相同的牌
if (dep == 3) //每次无论是顺子还是刻子,只有4组
{
return true;
}
number[i] -= 3; //用过了这三张牌
if (recursive(dep+1))
{
return true;
}
number[i] +=3;
}
}
for (i = 0; i < 24; i++)
{
//要成为顺子,最大的牌为7W
if (i%9 <= 6 && number[i] >=1 && number[i+1] >=1 && number[i+2] >=1 )
{
//可以为顺子
if (dep == 3) return true;//四组都找到了
number[i]--;
number[i+1]--;
number[i+2]--;
if (recursive(dep+1))
{
return true;
}
number[i]++;
number[i+1]++;
number[i+2]++;
}
}
return false;
}
bool check()
{
for (int i = 0 ; i < 34; i++)
{
if (number[i] >= 2)
{
//先找将牌
number[i] -=2;
if (recursive(0))
//可以和牌
return true;
number[i] +=2;
}
}
return false;
}
int main()
{
int kcase = 0,i,j;
bool hu;
string temp;
while (cin>>temp)
{
if (temp[0] == '0')
break;
cout<<"Case "<<++kcase<<":";
memset(number,0,sizeof(number));
number[convert(temp)]++;
for (i = 1; i < 13; i++)
{
cin>>temp;
number[convert(temp)]++;
}
hu = false;
memcpy(origin,number,sizeof(origin));
for (i = 0 ;i < 34; i++)
{
if (number[i] >= 4)
continue;//已经不能再多了
number[i]++;
if (check())
{
hu = true;
cout<<" "<<mahjong[i];
//如果胡牌,则number数组中的元素已经用完,需要重新赋值
memcpy(number,origin,sizeof(number));
continue;
}
//若没有胡牌,要减去当前新加进去的牌
number[i]--;
}
if (!hu)
{
cout<<" Not ready";
}
cout<<"\n";
}
return 0;
}
最后,欢迎关注我的个人博客。