题目链接https://vjudge.net/contest/305270#problem/I
题目大意:在麻将游戏中,有 34 种牌,分别是 1-9 的万,1-9 的筒,1-9 的条,以及 7 种字牌 “东”,“南”,“西”,“北”,“白”,“发”,“中”。
这 34 种牌各四张,共 136 张。
如果你手牌中凑够了 14张牌,满足一定的牌型条件,就称作“和牌”。
这个牌型有很多种,但在本题中,只考虑最基本的一种,4 个面子 + 1 个雀头组成的牌型。
面子是刻子和顺子的统称,雀头是对子。
刻子指的是,三张一样的牌。
顺子指的是,三张连续的牌,注意,只有非字牌(也就是万,筒,条)才能连续,例如一二三万,四五六筒,并且不能循环连续,比如九一二条就不算顺子。
对子指的是,两张一样的牌。
现在,你 手中有13 张牌,并且再得到某一张牌,就可以和牌,而你的目标就是输出能使 你和牌的牌
emmm,和HDU4331其实是一样的,暴力DFS回溯,枚举34种牌,判断是否可以和牌:我们用mjid保存每张牌的数量,mj保存的是牌的编号。
先打个表:
string sple[]={"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"};
for (int i=0; i<34; i++) {
memset(mjid,0,sizeof(mjid));
for (int j=0; j<13; j++) mjid[mj[j]]++;
if (mjid[i]>=4) continue;
mjid[i]++;
if (ok(i)) {
mark=1;
cout<<" "<<sple[i];
}
mjid[i]--;
}
if (!mark) printf (" Not ready");
cout<<endl;
下面关键的就是解决ok函数了。我们可以枚举对子的情况然后判断剩下的是否可以组成4个面子就好了,这个就需要用到dfs回溯了,我们可以将每张牌进行选择,即组成刻子或是顺子:
int check(int stp)
{
for (int i=0; i<34; i++){//组成刻子(3张相同的牌)
if (mjid[i]>=3){
if (stp==3) return 1;
mjid[i]-=3;
if (check(stp+1)) return 1;
mjid[i]+=3;
}
}
for (int i=0; i<25; i++){//组成顺子,前面数字为8、9的和字牌都是无用的
if (i%9>6) continue;//判断前面的数字是否为8、9
if (mjid[i] && mjid[i+1] && mjid[i+2]){
if (stp==3) return 1;
mjid[i]--;mjid[i+1]--;mjid[i+2]--;
if (check(stp+1)) return 1;
mjid[i]++;mjid[i+1]++;mjid[i+2]++;
}
}
return 0;
}
emmm,其实这两个for可以合并的。。。
以下是AC代码:
#include <bits/stdc++.h>
using namespace std;
string sple[]={"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"};
string s;
int mjid[40],mj[15];
int findid(string s);
int ok(int id);
int check(int stp);
int main()
{
int num=0,cas=1;
while (cin>>s){
if (s[0]=='0') break;
mj[num++]=findid(s);
if (num==13){
num=0;
int mark=0;
printf ("Case %d:",cas++);
for (int i=0; i<34; i++){
memset(mjid,0,sizeof(mjid));
for (int j=0; j<13; j++) mjid[mj[j]]++;
if (mjid[i]>=4) continue;
mjid[i]++;
if (ok(i)){
mark=1;
cout<<" "<<sple[i];
}
mjid[i]--;
}
if (!mark) printf (" Not ready");
cout<<endl;
}
}
return 0;
}
int findid(string s)
{
for (int i=0; i<34; i++)
if (s==sple[i]) return i;
}
int ok(int id)
{
for (int i=0; i<34; i++){
if (mjid[i]>=2){
mjid[i]-=2;
if (check(0)) return 1;
mjid[i]+=2;
}
}
return 0;
}
int check(int stp)
{
for (int i=0; i<34; i++){
if (mjid[i]>=3){
if (stp==3) return 1;
mjid[i]-=3;
if (check(stp+1)) return 1;
mjid[i]+=3;
}
}
for (int i=0; i<25; i++){
if (i%9>6) continue;
if (mjid[i] && mjid[i+1] && mjid[i+2]){
if (stp==3) return 1;
mjid[i]--;mjid[i+1]--;mjid[i+2]--;
if (check(stp+1)) return 1;
mjid[i]++;mjid[i+1]++;mjid[i+2]++;
}
}
return 0;
}