计蒜之道2019 复赛 B-个性化评测系统 (dfs搜索)

博客围绕计蒜之道2019复赛B - 个性化评测系统题目展开。题目是手中有十三张牌,求听哪些牌可胡牌,胡牌方式为4面子 + 一对子,面子含顺子和刻子。题解是记录牌数,枚举可听牌,暴力搜索所有情况,出现一种胡牌情况即可。还附上AC代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:
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;
}

欢迎评论!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值