题意:给出三种麻将胡的规则。给出你现在的手上的13张牌面,能否自摸一张牌,使自己胡。如果有,输出所有能够胡的牌。
思路:胡的规则中,后两种,因为牌型固定,可以直接暴力判读即可。最难处理的是第一种比较自由的牌型。
刚开始觉得和以前做过的斗地主的题目很像,直接记录有什么样的牌型,暴力判断。但是因为,在胡的牌型中,对和连和三对可以同时出现,如果只是记录有什么样的牌型,会导致重复使用一张牌。
这样只能搜索了。我们先找到能够成对的,然后搜索三连或者是三对。
注意点:因为题中的Test case比较多,如果用c++的写,判断三连或者是三对的搜索的姿势不好,和容易被卡掉的。(自己就是。。。)
注意对4张牌的特判。
代码如下:(不愿意写了。。转自kuangbin菊苣的)
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int cnt[35];
bool judge4X3()
{
int ret=0;
int tmp[35];
for(int i=0;i<34;i++)tmp[i]=cnt[i];
for(int i=0;i<=18;i+=9)
for(int j=0;j<9;j++)
{
if(tmp[i+j]>=3)
{
tmp[i+j]-=3;
ret++;
}
while(j+2<9 && tmp[i+j] && tmp[i+j+1] &&tmp[i+j+2])
{
tmp[i+j]--;
tmp[i+j+1]--;
tmp[i+j+2]--;
ret++;
}
}
for(int j=0;j<7;j++)
{
if(tmp[27+j]>=3)
{
tmp[27+j]-=3;
ret++;
}
}
if(ret==4)return true;
return false;
}
bool judge1()
{
for(int i=0;i<34;i++)
{
if(cnt[i]>=2)
{
cnt[i]-=2;//枚举对子
if(judge4X3())
{
cnt[i]+=2;
return true;
}
cnt[i]+=2;
}
}
return false;
}
bool judge2()
{
for(int i=0;i<34;i++)
{
if(cnt[i]!=2 && cnt[i]!=0)
return false;
}
return true;
}
bool judge3()
{
for(int j=0;j<7;j++)
if(cnt[j+27]==0)
return false;
for(int i=0;i<=18;i+=9)
{
if(cnt[i]==0 || cnt[i+8]==0)return false;
for(int j=1;j<8;j++)
if(cnt[i+j]!=0)
return false;
}
return true;
}
bool judge()
{
if(judge1() || judge2() || judge3())return true;
return false;
}
int main()
{
int T;
char str[10];
scanf("%d",&T);
int ans[35],tol;
while(T--)
{
memset(cnt,0,sizeof(cnt));
for(int i=0;i<13;i++)
{
scanf("%s",&str);
int t=str[0]-'1';
if(str[1]=='m')t+=0;
else if(str[1]=='s')t+=9;
else if(str[1]=='p')t+=18;
else t+=27;
cnt[t]++;
}
tol=0;
for(int i=0;i<34;i++)
{
cnt[i]++;
if(cnt[i]<=4 && judge())
ans[tol++]=i;
cnt[i]--;
}
if(tol==0)printf("Nooten\n");
else
{
printf("%d",tol);
for(int i=0;i<tol;i++)
{
printf(" %d",(ans[i]%9)+1);
if(ans[i]/9==0)printf("m");
else if(ans[i]/9==1)printf("s");
else if(ans[i]/9==2)printf("p");
else printf("c");
}
printf("\n");
}
}
return 0;
}