給定 13 張麻將牌(共 34 種,每種 4 張),判斷再摸哪一張牌可胡牌。胡牌定義:手牌可分為 1 個對子(眼)+ 4 個面子(刻子/順子)。不考慮特殊牌型(如七對、十三幺)。
cnt[34]。cnt[i] == 4 跳過;否則 cnt[i]++ 驗證能否胡牌。check():
i(cnt[i] >= 2),扣除 2 張。dfs(depth) 處理剩余 12 張牌:優先嘗試刻子(cnt[i] >= 3),再嘗試順子(僅數字牌且 i%9 <= 6)。depth == 4 成功返回 true。Not ready。#includeusing namespace std; const vector tile = { "1T","2T","3T","4T","5T","6T","7T","8T","9T", "1S","2S","3S","4S","5S","6S","7S","8S","9S", "1W","2W","3W","4W","5W","6W","7W","8W","9W", "DONG","NAN","XI","BEI","ZHONG","FA","BAI" }; int cnt[34], hand[13]; bool dfs(int formed) { if (formed == 4) return true; for (int i = 0; i < 34; ++i) { if (cnt[i] >= 3) { // 刻子 cnt[i] -= 3; if (dfs(formed + 1)) return true; cnt[i] += 3; } } for (int i = 0; i <= 24; ++i) { // 順子(僅數字牌) if (i % 9 <= 6 && cnt[i] && cnt[i+1] && cnt[i+2]) { cnt[i]--; cnt[i+1]--; cnt[i+2]--; if (dfs(formed + 1)) return true; cnt[i]++; cnt[i+1]++; cnt[i+2]++; } } return false; } bool canWin() { for (int i = 0; i < 34; ++i) if (cnt[i] >= 2) { cnt[i] -= 2; if (dfs(0)) { cnt[i] += 2; return true; } cnt[i] += 2; } return false; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string s; int tc = 1; while (cin >> s, s != "0") { hand[0] = find(tile.begin(), tile.end(), s) - tile.begin(); for (int i = 1; i < 13; ++i) { cin >> s; hand[i] = find(tile.begin(), tile.end(), s) - tile.begin(); } cout << "Case " << tc++ << ":"; bool any = false; for (int i = 0; i < 34; ++i) { fill(cnt, cnt+34, 0); for (int h : hand) ++cnt[h]; if (cnt[i] == 4) continue; ++cnt[i]; if (canWin()) { cout << ' ' << tile[i]; any = true; } } if (!any) cout << " Not ready"; cout << '\n'; } return 0; }
cnt 壓縮為 64 位整數)進一步加速,但非必要。i%9 區分花色,避免跨花色順子。本題是「狀態空間小、規則固定」類問題的典型:枚舉決策點 + 回溯驗證。麻將胡牌判斷邏輯可抽象為「多重集合劃分為固定模式」,同樣適用於日本麻將、撲克牌型判斷等場景。