算法
回溯算法(递归)
思路
如果手中的14张牌是能和牌的,那么这14张牌分别参与雀头、顺子、刻子。进一步,把牌分成两部分,遍历牌数大于二的牌,让这些牌作为雀头,对剩下的牌,要么参与顺子的构造,要么参与刻子的构造。
根据这样的分析,分两层回溯算法。
特别的,对于牌数是4的牌,有两种组合方法:这四张牌参与到四个顺子中或者这四张牌中三张作为刻子,另外一张参与一个顺子
代码
#include<iostream>
#include<vector>
using namespace std;
bool check_cards(int* cards, int k) {
if (k == 9)
return true;
if (cards[k] == 0)
return check_cards(cards, k + 1);
int temp = cards[k];
for (int i = k - 2; i <= k; i++) {
if (i >= 0 && i + 2 < 9
&& cards[i] >= temp && cards[i + 1] >= temp && cards[i + 2] >= temp) {
cards[i] -= temp;
cards[i + 1] -= temp;
cards[i + 2] -= temp;
if (check_cards(cards, k + 1))
return true;
cards[i] += temp;
cards[i + 1] += temp;
cards[i + 2] += temp;
}
}
if (temp == 3) {
cards[k] -= 3;
if (check_cards(cards, k + 1))
return true;
cards[k] += 3;
}
if (temp == 4) {
temp = 1;
for (int i = k - 2; i <= k; i++) {
if (i >= 0 && i + 2 < 9
&& cards[i] >= temp && cards[i + 1] >= temp && cards[i + 2] >= temp) {
cards[i] -= temp;
cards[i + 1] -= temp;
cards[i + 2] -= temp;
cards[k] -= 3;
if (check_cards(cards, k + 1))
return true;
cards[i] += temp;
cards[i + 1] += temp;
cards[i + 2] += temp;
cards[k] += 3;
}
}
}
return false;
}
int main(void) {
int cards[9] = { 0 }, cards_bk[9] = { 0 };
for (int i = 0; i < 13; i++) {
int j;
cin >> j;
cards[j - 1]++;
}
for (int i = 0; i < 9; i++)
cards_bk[i] = cards[i];
vector<int> oks;
for (int i = 0; i < 9; i++) {
if (cards[i] == 4)
continue;
for (int i = 0; i < 9; i++)
cards[i] = cards_bk[i];
cards[i]++;
int ok = 0;
for (int j = 0; j < 9 && !ok; j++) {
//取雀头-对j
if (cards[j] < 2)
continue;
cards[j] -= 2;
if (check_cards(cards, 0)) {
ok = 1;
oks.push_back(i + 1);
}
cards[j] += 2;
}
cards[i]--;
}
if (oks.size() == 0)
cout << 0;
else
for (int i = 0; i < oks.size(); i++) {
cout << oks[i];
if (i != oks.size() - 1)
cout << ' ';
}
}