现在的位置: 首页 > 综合 > 正文

HDU 4431 Mahjong(12天津A题)#by zh

2018年04月23日 ⁄ 综合 ⁄ 共 2907字 ⁄ 字号 评论关闭

超蛋疼模拟题,尤其是对我这个不会玩麻将的人来说,根本不知道该怎么判断胡牌,在网上搜到了一个判断胡牌的算法,这个只能判断那种最一般的情况,七小对和十三幺都没有。不过这两个也不怎么难,我把模版贴过来自己写了这两个函数,华丽丽的wa了,改了半天又和网上求这两种和法的函数比较才改好,真心伤不起,还是我代码能力太弱了……

#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <map>
#include <vector>
#include <cmath>
using namespace std;
map<char,int> convert;
vector<string> ans;
int card[4][10];
char str[5];
int appear[100];
bool Win(int [4][10]);
bool Analyze(int [],bool);
bool Win (int allPai[4][10])
{
    int jiangPos;//“将”的位置
    int yuShu;//余数
    bool jiangExisted=false;
    //是否满足3,3,3,3,2模型
    for(int i=0; i<4; i++)
    {
        //yuShu=(int)fmod(allPai[i][0],3);
        yuShu=allPai[i][0]%3;
        if (yuShu==1)
        {
            return false;
        }
        if (yuShu==2)
        {
            if (jiangExisted)
            {
                return false;
            }
            jiangPos=i;
            jiangExisted=true;
        }
    }
    for(int i=0; i<4; i++)
    {
        if (i!=jiangPos)
        {
            if (!Analyze(allPai[i],i==3))
            {
                return false;
            }
        }
    }
    //该类牌中要包含将,因为要对将进行轮询,效率较低,放在最后
    bool success=false;//指示除掉“将”后能否通过
    for(int j=1; j<10; j++) //对列进行操作,用j表示
    {
        if (allPai[jiangPos][j]>=2)
        {
            //除去这2张将牌
            allPai[jiangPos][j]-=2;
            allPai[jiangPos][0]-=2;
            if(Analyze(allPai[jiangPos],jiangPos==3))
            {
                success=true;
            }
            //还原这2张将牌
            allPai[jiangPos][j]+=2;
            allPai[jiangPos][0]+=2;
            if (success) break;
        }
    }
    return success;
}
//分解成“刻”“顺”组合
bool Analyze(int aKindPai[],bool ziPai)
{
    if (aKindPai[0]==0)
    {
        return true;
    }
//寻找第一张牌
    int j;
    for(j=1; j<10; j++)
    {
        if (aKindPai[j]!=0)
        {
            break;
        }
    }
    bool result;
    if (aKindPai[j]>=3)//作为刻牌
    {
        //除去这3张刻牌
        aKindPai[j]-=3;
        aKindPai[0]-=3;
        result=Analyze(aKindPai,ziPai);
        //还原这3张刻牌
        aKindPai[j]+=3;
        aKindPai[0]+=3;
        return result;
    }
    //作为顺牌
    if ((!ziPai)&&(j<8)
            &&(aKindPai[j+1]>0)
            &&(aKindPai[j+2]>0))
    {
        //除去这3张顺牌
        aKindPai[j]--;
        aKindPai[j+1]--;
        aKindPai[j+2]--;
        aKindPai[0]-=3;
        result=Analyze(aKindPai,ziPai);
        //还原这3张顺牌
        aKindPai[j]++;
        aKindPai[j+1]++;
        aKindPai[j+2]++;
        aKindPai[0]+=3;
        return result;
    }
    return false;
}
bool isAllpair(int allPai[4][10])
{
    int c=0;
    for(int i=0;i<4;i++)
    {
        if(allPai[i][0]%2)
            return false;
        for(int j=1;j<10;j++)
        {
            if(allPai[i][j]==2)
                c++;
        }
    }
    return c==7;
}
bool otherjudge(int allPai[4][10])
{
    int c1=0,c2=0;
    for(int i=0;i<3;i++)
    {
        if(allPai[i][1]>=1)
        {
            c1++;
            if(allPai[i][1]==2)
                c2++;
        }
        if(allPai[i][9]>=1)
        {
            c1++;
            if(allPai[i][9]==2)
                c2++;
        }
    }
    for(int i=1;i<=7;i++)
        if(allPai[3][i]>=1)
        {
            c1++;
            if(allPai[3][i]==2)
                c2++;
        }
    return c1==13&&c2==1;
}
bool judge()
{
    memset(card,0,sizeof(card));
    int tot=0;
    for(int i=1; i<=37; i++)
    {
        if(i%10==0)
        {
            continue;
        }
        card[i/10][i%10]=appear[i];
        card[i/10][0]+=appear[i];
    }
    if(Win(card))
        return true;
    else if(isAllpair(card))
        return true;
    else if(otherjudge(card))
        return true;
    else return false;
}
int main()
{
    //freopen("input.txt","r",stdin);
    int t;
    scanf("%d",&t);
    convert['m']=0;
    convert['s']=10;
    convert['p']=20;
    convert['c']=30;
    while(t--)
    {
        ans.clear();
        memset(appear,0,sizeof(appear));
        for(int i=0; i<13; i++)
        {
            scanf("%s",str);
            appear[str[0]-'0'+convert[str[1]]]++;
        }
        for(int i=1; i<=37; i++)
        {
            if(i%10==0||appear[i]>=4)
                continue;
            appear[i]++;
            if(judge())
            {
                string temp="";
                temp+=(i%10)+'0';
                if(i<10)
                    temp+="m";
                else if(i<20)
                    temp+="s";
                else if(i<30)
                    temp+="p";
                else temp+="c";
                ans.push_back(temp);
            }
            appear[i]--;
        }
        if(ans.size())
        {
            printf("%d",ans.size());
            for(int i=0;i<ans.size();i++)
                cout<<" "<<ans[i];
            cout<<endl;
        }
        else cout<<"Nooten"<<endl;
    }
}

抱歉!评论已关闭.