原题链接:
https://nanti.jisuanke.com/t/39612
题意:
手里有十三张牌,问可以听那些牌后胡牌。
胡牌方式采用4面子+一对子的方式。
面子包含:顺子和刻子(三个相同的牌)
每种牌的数量仅有4张。
题解:
记录手里每张牌的数量,枚举可以听的牌,暴力搜索所有可能的情况,只要出现一种情况可以胡牌,则可以听这张牌。
附上AC代码:
#include <bits/stdc++.h>
using namespace std;
string str[20];
int num[5][10];
char c[5]={'a','m','s','p','z'};
int a[5][10];
bool f=false;
void dfs(int x,int y,int sz,int dz)
{
if(f||sz>4||dz>1)return ;//如果已经可以胡牌或已经确定不可以胡牌,则返回
if(sz==4&&dz==1)//可以胡牌,f=true
{
f=true;
return ;
}
for(int i=x;i<=3;i++)//继续向后搜索
{
int j=y;
if(i!=x) j=1;
for(;j<=9;j++)
{
if(a[i][j]==0)continue;//该牌为数量为0,跳过
else if(a[i][j]==1)//该牌为数量为1,看是否可以组成顺子
{
if(j+2<=9&&a[i][j+1]>=1&&a[i][j+2]>=1)
{
a[i][j]--,a[i][j+1]--,a[i][j+2]--;
dfs(i,j,sz+1,dz);
a[i][j]++,a[i][j+1]++,a[i][j+2]++;
}
}
else if(a[i][j]==2)//该牌为数量为2,两种分法:
{
if(j+2<=9&&a[i][j+1]>=2&&a[i][j+2]>=2)//分别组成两个顺子
{
a[i][j]-=2,a[i][j+1]-=2,a[i][j+2]-=2;
dfs(i,j,sz+2,dz);
a[i][j]+=2,a[i][j+1]+=2,a[i][j+2]+=2;
}
//或者组成一个对子
a[i][j]-=2;
dfs(i,j,sz,dz+1);
a[i][j]+=2;
}
else if(a[i][j]==3)//3种分法
{
if(j+2<=9&&a[i][j+1]>=3&&a[i][j+2]>=3)//3个顺子
{
a[i][j]-=3,a[i][j+1]-=3,a[i][j+2]-=3;
dfs(i,j,sz+3,dz);
a[i][j]+=3,a[i][j+1]+=3,a[i][j+2]+=3;
}
if(j+2<=9&&a[i][j+1]>=1&&a[i][j+2]>=1)//1顺子+一对子
{
a[i][j]-=3,a[i][j+1]--,a[i][j+2]--;
dfs(i,j,sz+1,dz+1);
a[i][j]+=3,a[i][j+1]++,a[i][j+2]++;
}
//一刻子
a[i][j]-=3;
dfs(i,j,sz+1,dz);
a[i][j]+=3;
}
else if(a[i][j]==4)//两种有效分法
{
if(j+2<=9&&a[i][j+1]>=4&&a[i][j+2]>=4)//4个顺子
{
a[i][j]-=4,a[i][j+1]-=4,a[i][j+2]-=4;
dfs(i,j,sz+4,dz);
a[i][j]+=4,a[i][j+1]+=4,a[i][j+2]+=4;
}
if(j+2<=9&&a[i][j+1]>=1&&a[i][j+2]>=1)//1顺子+一刻子
{
a[i][j]-=4,a[i][j+1]-=1,a[i][j+2]-=1;
dfs(i,j,sz+2,dz);
a[i][j]+=4,a[i][j+1]+=1,a[i][j+2]+=1;
}
}
}
}
if(x!=4)
for(int j=1;j<=7;j++)
{
if(a[4][j]==0)continue;//该牌为数量为0,跳过
else if(a[4][j]==1)//该牌为数量为1,没有有效分法
{
continue;
}
else if(a[4][j]==2)//该牌为数量为2,一对子
{
a[4][j]-=2;
dfs(4,j,sz,dz+1);//dz++;//
a[4][j]+=2;
}
else if(a[4][j]==3)//该牌为数量为3,一刻子
{
a[4][j]-=3;
dfs(4,j,sz+1,dz);//sz++;//
a[4][j]+=3;
}
else if(a[4][j]==4)//该牌为数量为4,没有有效分法
{
continue;
}
}
else
{
for(int j=y;j<=7;j++)
{
if(a[4][j]==0)continue;//该牌为数量为0,跳过
else if(a[4][j]==1)//该牌为数量为1,没有有效分法
{
continue;
}
else if(a[4][j]==2)//该牌为数量为1,没有有效分法
{
a[4][j]-=2;
dfs(4,j,sz,dz+1);//该牌为数量为2,一对子
a[4][j]+=2;
}
else if(a[4][j]==3)//该牌为数量为3,一刻子
{
a[4][j]-=3;
dfs(4,j,sz+1,dz);
a[4][j]+=3;
}
else if(a[4][j]==4)//该牌为数量为4,没有有效分法
{
continue;
}
}
}
if(sz==4&&dz==1)//可以胡牌,f=true
{
f=true;
return ;
}
return ;
}
bool check(int x,int y)
{
for(int i=1;i<=4;i++)//复制一遍各个麻将的个数
{
for(int j=1;j<=9;j++)
{
a[i][j]=num[i][j];
}
}
a[x][y]++;
if(a[x][y]>4)//如果超过四张牌,则表示不可能
{
return false;
}
dfs(1,1,0,0);//搜索是否存在合理解
if(f) return true;
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
while(cin>>str[0])//注意是多组数据
{
memset(num,0,sizeof(num));
for(int i=0;i<13;i++)//计算每个麻将的个数
{
if(i>0)
cin>>str[i];
if(str[i][1]=='m')
{
num[1][str[i][0]-'0']++;
}
else if(str[i][1]=='s')
{
num[2][str[i][0]-'0']++;
}
else if(str[i][1]=='p')
{
num[3][str[i][0]-'0']++;
}
else if(str[i][1]=='z')
{
num[4][str[i][0]-'0']++;
}
}
for(int i=1;i<=3;i++)//枚举听牌:万,条,筒
for(int j=1;j<=9;j++)
{
if(check(i,j))
cout<<j<<c[i]<<endl;
f=false;
}
for(int i=1;i<=7;i++)//枚举听牌 :东南西北中发白
{
if(check(4,i))
cout<<i<<c[4]<<endl;
f=false;
}
}
return 0;
}
欢迎评论!