HDU 4431 Mahjong

题目描述
Japanese Mahjong is a four-player game. The game needs four people to sit around a desk and play with a set of Mahjong tiles. A set of Mahjong tiles contains four copies of the tiles described next:
这里写图片描述

A winning state means a set of 14 tiles that normally contains a pair of same tiles (which we call “eyes”) and four melds. A meld is formed by either three same tiles(1m, 1m, 1m or 2c, 2c, 2c for example) or three continuous non-character tiles(1m, 2m, 3m or 5s, 6s, 7s for example).

However, there are two special winning states that are different with the description above, which are:
“Chii Toitsu”, which means 7 different pairs of tiles;
“Kokushi Muso”, which means a set of tiles that contains all these tiles: 1m, 9m, 1p, 9p, 1s, 9s and all 7 character tiles. And the rest tile should also be one of the 13 tiles above.

And the game starts with four players receiving 13 tiles. In each round every player must draw one tile from the deck one by one. If he reaches a winning state with these 14 tiles, he can say “Tsu Mo” and win the game. Otherwise he should discard one of his 14 tiles. And if the tile he throws out can form a winning state with the 13 tiles of any other player, the player can say “Ron” and win the game.

Now the question is, given the 13 tiles you have, does there exist any tiles that can form a winning state with your tiles?

(Notes: Some of the pictures and descriptions above come from Wikipedia.)

Input
The input data begins with a integer T(1≤T≤20000). Next are T cases, each of which contains 13 tiles. The description of every tile is as above.

Output
For each cases, if there actually exists some tiles that can form a winning state with the 13 tiles given, print the number first and then print all those tiles in order as the description order of tiles above. Otherwise print a line “Nooten”(without quotation marks).

Sample Input
2
1s 2s 3s 2c 2c 2c 2p 3p 5m 6m 7m 1p 1p
1p 1p 2p 3p 4s 5s 6s 7c 7c 3s 3s 2m 2m

Sample Output
2 1p 4p
Nooten

大致题意
给你13张牌,问再添加一张牌,问是否可以胡牌。如果可以则先输出方案数然后顺序输出添加的牌,否则输出Nooten。

思路
模拟+枚举。首先枚举3*9+7=34种牌,然后判断添加的牌是否可以胡牌,可以的话则将其存入字符串中然后方案数+1,最后输出。
有三种方式可以胡牌:

1.一个对子+4组3张相同的牌或顺子(比如1m2m3m 或者1m1m1m),可以先枚举所选的对子,然后再找符合条件的顺子和3张相同的牌,如果能找到4个满足条件的则可以胡牌。
(c是没有顺子的)

2.有7个不同的对子,满足该条件的情况是每种牌的数量不是0就是2,遍历即可。

3.有1m, 9m, 1p, 9p, 1s, 9s,1c,2c,3c,4c,5c,6c,7c这13张牌然后剩下的一张也是在这13种牌当中。满足该条件的情况是这13种牌的数量每个都不为0,且相加起来数量为14.

坑点:如果某种牌的数量已经为4了则不能再添加该种牌,然后最后的输出末尾不要多空格。
(这两个地方被卡了好久。。。)

下面是代码,

#include <iostream> 
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <math.h>
#include <algorithm>
#include <climits>
#include <cstring>
#include <string>
#include <set>
#include <queue>
#include <stack>
#include <vector>
#include <list>
#include<sstream>
#include<ctime>
using namespace std;
int m[10],s[10],p[10],c[10]; //记录每种牌的数量

int judge()   //判断是否可以找到4组3张相同的牌或顺子
{
    int cnt=0,m1[10],s1[10],p1[10],c1[10];//辅助数组,维护原数组
    for(int i=1;i<=9;i++) // 给辅助数组赋值
    {
        m1[i]=m[i];
        s1[i]=s[i];
        p1[i]=p[i];
        c1[i]=c[i]; 
     }
     for(int i=1;i<=9;i++)  //m,s,p这三类牌是1到9
     {
        if(m1[i]>=3)   //先找m类 ,如果相同牌的数量大于等于3则选择。
        {
            cnt++;         // 找到了一组cnt++
            m1[i]-=3;       //  选择了后将该牌的数量减3
        }
        if(i<=7)
        {
            while(m1[i]>0&&m1[i+1]>0&&m1[i+2]>0) //这里注意用while循环找顺子,如果只用一条if来找会出错,比如1m1m2m2m3m3m,你找到一组1m2m3m后就i++了(这里我也卡了好久)
            {                                  
                cnt++;      //找到一组后cnt++,将选择的牌数量减一。
                m1[i]--;
                m1[i+1]--;
                m1[i+2]--; 
            }
        }


        if(s1[i]>=3) //找s类 ,方法同上
        {
            cnt++;
            s1[i]-=3;
        }
        if(i<=7)
        {
            while(s1[i]>0&&s1[i+1]>0&&s1[i+2]>0)
            {
                cnt++;
                s1[i]--;
                s1[i+1]--;
                s1[i+2]--; 
            }
        }

        if(p1[i]>=3)  //找p类,方法同上
        {
            cnt++;
            p1[i]-=3;
        }
        if(i<=7)
        {
            while(p1[i]>0&&p1[i+1]>0&&p1[i+2]>0)
            {
                cnt++;
                p1[i]--;
                p1[i+1]--;
                p1[i+2]--; 
            }
        }
    } 
    for(int i=1;i<=7;i++) //找c类,由于c类不可能有顺子,所以只用考虑找相同的三张牌
    {                     //方法同上
        if(c1[i]==3)
        {
            cnt++;
            c1[i]-=3;
        }
    }
    if(cnt==4) return 1;  //如果能找到4组 则返回1
    else return 0;        //否则返回0
}

int p1()    // 进行第一种胡牌方法的判断
{
    for(int i=1;i<=9;i++)  //m,s,p这三类牌是1到9
    {
        if(m[i]>=2)   // 先找m类,如果mi的数量大于等于二,则选其作为对子
        {
            m[i]-=2;    // 数量减二
            if(judge())  //进行判断以mi作为对子是否可以胡牌,judge()返回值若为1则可以胡牌
            {
            m[i]+=2;       // 将数组恢复原来数量,以便后续判断
            return 1;      //如果能胡牌则返回1
           }
            m[i]+=2;      // 将数组恢复原来数量,以便后续判断
        }
        if(s[i]>=2)   //找s类,方法同上
        {
            s[i]-=2;
            if(judge())
            {
                s[i]+=2;
               return 1;
          }
            s[i]+=2;
        }
        if(p[i]>=2)  // 找p类,方法同上
        {
            p[i]-=2;
            if(judge())
            {
              p[i]+=2;
              return 1;
            }
            p[i]+=2;
        }
    }
    for(int i=1;i<=7;i++)   //找c类,方法同上
    {
        if(c[i]>=2)
        {
            c[i]-=2;
            if(judge())
            {
                c[i]+=2;
               return 1;
            }
            c[i]+=2;
        }
    }
    return 0;  //第一种胡牌方法不行,返回0
}

int p2() // 进行第二种胡牌方法的判断
{
    for(int i=1;i<=9;i++)   // 如果有牌的数量不为0或者2,则第二种胡牌方法不行,返回0
    {
        if(m[i]!=0&&m[i]!=2)
        {
            return 0;
        }
        if(s[i]!=0&&s[i]!=2)
        {
            return 0;
        }
        if(p[i]!=0&&p[i]!=2)
        {
            return 0;
        } 
    }
    for(int i=1;i<=7;i++)
    {
        if(c[i]!=0&&c[i]!=2)
        return 0;
    }
    return 1;   //第二种方法可以,返回1
}

int p3()  // 进行第三种胡牌方法的判断,可行返回1,不行返回0
{
    int sum=0;
    for(int i=1;i<=7;i++)
    {
        if(c[i]==0)
        return 0;
        sum+=c[i];
    }
    if(m[1]>0&&m[9]>0&&p[1]>0&&p[9]>0&&s[1]>0&&s[9]>0)
    {
        sum+=m[1]+m[9]+s[1]+s[9]+p[1]+p[9];
        if(sum==14)
        return 1;
    }
    return 0;
}
int puanduan()   //进行三种胡牌方法的判断,只要有一种可行就返回1,都不行则返回0
{
    if(p1())
    {
      return 1;
    }
    if(p2())
    {

        return 1;
    }
    if(p3())
    {

    return 1;
   }
    return 0;
}
int main()  
{     
     int t,sum,k;
     cin>>t;
     while(t--)
     {
        char str[1000];   //存可胡牌的添加牌
        sum=0;             //初始化
        k=0;
        memset(m,0,sizeof(m));
        memset(s,0,sizeof(s));
        memset(p,0,sizeof(p));
        memset(c,0,sizeof(c));
        int x;
        char cc;
        for(int i=1;i<=13;i++)  //读入数据
        {
            scanf("%d%c",&x,&cc);
            if(cc=='m')
            {
                m[x]++;
            }
            else if(cc=='s')
            {
                s[x]++;
            }
            else if(cc=='p')
            {
                p[x]++;
            }
            else if(cc=='c')
            {
                c[x]++;
            }
        }

        for(int i=1;i<=9;i++)  //先是m类,枚举添加的牌
        {
            if(m[i]<4)  //如果该牌的数量小于4
            { 
            m[i]++;   //添加该牌
            if(puanduan())  //如果添加的牌可以胡牌
            {
                sum++;     //方案数加1,将该牌保存
                str[k++]=i+'0';
                str[k++]='m';
                str[k++]=' ';
            }
            m[i]--;   //恢复
          }
        }
        for(int i=1;i<=9;i++)// s类,方法同上
        {
            if(s[i]<4)
            {

            s[i]++;
            if(puanduan())
            {
                sum++;
                str[k++]=i+'0';
                str[k++]='s';
                str[k++]=' ';
            }
            s[i]--;
            }
         } 
        for(int i=1;i<=9;i++) //p类,方法同上
        {
            if(p[i]<4)
           {

            p[i]++;
            if(puanduan())
            {
                sum++;
                str[k]=i+'0';
                k++;
                str[k]='p';
                k++;
                str[k]=' ';
                k++;
            }
            p[i]--;
           }
         } 
         for(int i=1;i<=7;i++) //c类,方法同上
         {
            if(c[i]<4)
            {

            c[i]++;
            if(puanduan())
            {
                sum++;
                str[k++]=i+'0';
                str[k++]='c';
                str[k++]=' ';
            }
            c[i]--;
           }
         } 
         k--;
         str[k]='\0';
         if(sum==0)            //输出结果
         cout<<"Nooten"<<endl;
         else 
         cout<<sum<<' '<<str<<endl;
     }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值