2021 ICPC昆明站 K Riichi!! 题解(妈妈再也不用担心孩子不会打麻将了)

题目通道(link of the problem)

题面(The Problem):

题面简直长的要死,一看就是大模拟,队里可能就我打过麻将,我直接拿来读了,比赛的时候看了我好久。
牛客题面截图

题目大概意思(Meaning of the problem):

给你一手14张的手牌,判断打掉打哪一张听牌并且输出对应的听的牌,如果已经胡了的话直接输出Tasumo
众所周知(bushi)麻将胡牌要一对雀头(指的是两张一样的牌)剩下来要全部是碰(三个相同)或者吃(三个按照顺序的牌)(其实是中间没有杠或者碰或者吃之判断手牌)

思路(Methods):

大模拟首先要思考好枚举方法。
1.先枚举打掉的牌,共14次

2.枚举抽到的的牌,共14种

3.枚举雀头,有雀头继续向下判断,无雀头肯定无法胡牌,并将雀头从排牌堆中去掉

4.DFS,枚举所有顺子和碰子(3个相同)每次操作均删除掉临时结构体中相应的牌,最后判断牌堆是否为空,为空则加入输出队列。

代码(Code):

#include "bits/stdc++.h"
#define endl "\n"

using namespace std;

map<char, int>mjNum;
char _mjName[] = "wbsz";

struct tiles {
    int num[10], backup[10];
    char type;
    void back() {
        for (int i = 0; i < 10; ++i) {
            backup[i] = num[i];
        }
        return;
    }
    void renew() {
        for (int i = 0; i < 10; ++i) {
            num[i] = backup[i];
        }
        return;
    }
    void output() {
        for (int i = 0; i < 10; ++i) {
            if (num[i]) {
                cout << "there are " << num[i] << " " << i << type << endl;
            }
        }
        return;
    }
    void init(char ch) {
        memset(num, 0, sizeof(num));
        type = ch;
        return;
    }
    bool check_zi() {
        //cout << "++++check zi+++++" << endl;output();
        for(int i = 1; i <= 7; ++i) {
                //cout << "check_zi find in " << i << " with num " << num[i] << endl;
                if (num[i] % 3 != 0) {
                    //cout << "check zi break in " << i << type << " with the value of " << num[i] << endl;
                    return false;
                }
        }
        //cout << "check_zi is Success" <<endl;
        return true;
    }
    bool check3() {
        for (int i = 1; i <= 9; ++i) {
            if (num[i]) {
                if (num[i] >= 3) {
                    //cout << i << type << " hase delete in size of 3" << endl;
                    tiles temp = *this;
                    temp.num[i] -= 3;
                    if (temp.check3()) return true;
                }
                if (i + 2 <= 9 && num[i + 1] > 0 && num[i + 2] > 0) {
                    tiles temp = *this;
                    temp.num[i + 1]--, temp.num[i]--,temp.num[i + 2]--;
                    if (temp.check3()) return true;
                }
                return false;
            }
        }
        return true;
    }
//    bool check3() {
//        back();
//        //cout << "====bef renew=====" << endl;output();
//        bool checkrsl = check3_in();
//        renew();
//        //cout << "====after renew====" << endl;output();
//        return checkrsl;
//    }
};

struct outputRow {
    pair<char, int>type;
    vector<pair<char, int>>addTail;
    void init() {
        type.first = 'a';
        addTail.clear();
        return;
    }
    void printAline() {
        cout << type.second << type.first << ' ';
        for (auto it : addTail) {
            cout << it.second << it.first;
        }
        cout << endl;
        return;
    }
};

struct table {
    tiles mj[4];
    //tiles mjBackup[4];
    vector<outputRow>expert;
    outputRow outputRowTemp;
    void init() {
        expert.clear();
        outputRowTemp.init();
        for (int i = 0; i < 4; ++i) {
            mj[i].init(_mjName[i]);
            //mjBackup[i] = mj[i];
        }
        return;
    }
//    void renew() {
//        for (int i = 0; i < 4; ++i) {
//            mj[i] = mjBackup[i];
//        }
//    }
    bool check3() {
        for (int i = 0; i < 3; ++i) {
            if (!mj[i].check3()) {
                //cout << "check3 break in " << _mjName[i] << endl;
                return false;
            }
        }
        //cout << "check in 3 in table's check3 function is Success" << endl;
        if (!mj[3].check_zi()) return false;
        //cout << "check in zi in table's check3 function is Success" << endl;
        return true;
    }
    bool check() {
        bool have2 = false;
        for (int i = 0; i < 4; ++i) {
            for (int j = 1; j < 10; ++j) {
                if (i == 3 && j == 8) break;
                if (mj[i].num[j] >= 2) {
                    table temp = *this;
                    temp.mj[i].num[j] -= 2;
                    if (temp.check3()) return true;
                }
            }
        }
        return have2;
    }
    bool getTail() {
        for (int i = 0; i < 4; ++i) {
            for (int j = 1; j <= 9; ++j) {
                if (i == 3 && j == 8) break;
                mj[i].num[j]++;
                //cout << "====add tile in " << j << _mjName[i] << "=======" << endl;
                if(check()) {
                    //cout << "outputrow was pushed in " << i << ',' << j << endl;
                    outputRowTemp.addTail.emplace_back(_mjName[i], j);
                }
                mj[i].num[j]--;
            }
        }
        return true;
    }
    void printSteps() {
        cout << expert.size() << endl;
        for (auto it : expert) {
            it.printAline();
        }
        return;
    }
    void find() {
//        for (int i = 0; i < 4; ++i) {
//            mjBackup[i] = mj[i];
//        }
        if (check()) {
            cout << "Tsumo!\n";
            return;
        }
        for (int i = 0; i < 4; ++i) {
            for (int j = 1; j <= 9; ++j) {
                if (mj[i].num[j]) {
                    mj[i].num[j]--;
                    outputRowTemp.init();
                    //cout << "===del " << j << _mjName[i] << " to get tails====" << endl;
                    //cout << "purchase with" << j << _mjName[i] << endl;
                    getTail();
                    if (!outputRowTemp.addTail.empty()) {
                        //cout << "expert was pushed in " << i << j << endl;
                        outputRowTemp.type = {_mjName[i], j};
                        expert.push_back(outputRowTemp);
                    }
                    mj[i].num[j]++;
                }
            }
        }
        printSteps();
        return;
    }
};


int main(void) {
    int t;
    for (int i = 0; i < 4; ++i) {
        mjNum[_mjName[i]] = i;
    }
    cin >> t;
    while (t--) {
        table play;
        string str;
        cin >> str;
        play.init();
        for (int i = 0; i < 28; i += 2) {
            string now = str.substr(i, 2);
            play.mj[mjNum[now[1]]].num[now[0] - '0']++;
        }
        //cout << "input test :" << endl;for (int i = 0; i < 4; ++i) play.mj[i].output();
        play.find();
    }

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值