我之前的答案已被删除,因为我没有真正提供解释,只是提供了一个脚本链接,其中包含针对此问题的算法。我意识到为什么这不适合现在堆栈溢出的答案。这是我对完整答案的尝试。
我在此处展示的算法基于此处找到的方法:https://gist.github.com/yalue/2622575。解决方案是上面 Paul Hankin 建议的回溯搜索。
算法创建了一个名为MeldNode的对象:
class MeldNode {
Cards cards;
MeldNode* parent;
double value;
MeldNode(Cards cards, MeldNode* parent) : cards(cards), parent(parent) {
value = sum of values of cards;
if (parent is not null){
value += parent->value;
}
}
}
这里的值等于提供的卡的卡值与父卡的值之和。
创建了一个函数cleanMeldGroup,给定一个融合数组和一个融合,它将返回一个融合数组,其中只有与给定融合不冲突的融合。
Melds cleanMeldGroup(Melds melds, Cards meldAvoid) {
Melds cleanMelds;
for (Cards meld : melds) {
bool clean = true;
for (Card cardA : meld) {
for (Card cardB : meldAvoid) {
if (cardA == cardB) {
clean = false;
}
}
}
if (clean) {
cleanMelds.push(meld);
}
}
return cleanMelds;
}
接下来,创建一个函数getBestNode,它使用回溯来找到一个包含最佳融合组合数据的融合节点。
MeldNode* getBestNode(Melds melds, MeldNode* rootNode) {
MeldNode* best = rootNode;
for (Meld meld : melds) {
MeldNode* node = new MeldNode(meld, rootNode);
MeldNode* newTree = getBestNode(cleanMeldGroup(melds, meld), node);
if (best is null || newTree->value > best->value){
best = newTree;
}
}
}
请注意,由于这是现在编写的,这将导致 c++ 中的内存泄漏。如有必要,在数据已使用时采取措施释放内存(您可以在此函数中释放不属于最佳树的节点的内存,然后释放属于最佳树的节点的内存)你使用它们)。
最后,可以使用getOptimalMelding 函数确定最佳融合如下。
Melds getOptimalMelding(Cards hand) {
Sort hand by rank and then by suit;
Melds possibleMelds;
// Find all possible runs
int runLength = 1;
for (int i = 0; i < hand.size(); i++) {
if (hand[i].suit == hand[i - 1].suit && hand[i].rank == hand[i - 1].rank + 1) {
runLength++;
} else {
if (runLength >= 3) {
for (int size = 3; size <= runLength; size++) {
for (int start = 0; start <= runLength - size; start++) {
Cards run;
for (int j = i - runLength + start; j < i - runLength + start + s; j++) {
run.push(hand[j]);
}
possibleMelds.push(run);
}
}
}
runLength = 1;
}
}
if (runLength >= 3) {
for (int size = 3; size <= runLength; size++) {
for (int start = 0; start <= runLength - size; start++) {
Cards run;
for (int j = i - runLength + start; j < i - runLength + start + s; j++) {
run.push(hand[j]);
}
possibleMelds.push(run);
}
}
}
// Find all possible sets
for (int i = 1; i <= 13; i++) {
Cards set;
for (Card card : hand) {
if (card.rank == i) {
set.push(card);
}
}
if (set.size() >= 3) {
possibleMelds.push(set);
}
if (set.size() == 4) {
for (Card card : set) {
Cards subset;
for (Card add : set) {
if (add != card) {
subset.push(add);
}
}
possibleMelds.push(subset);
}
}
}
// Find Optimal Melding Combination
MeldNode* bestNode = getBestNode(possibleMelds, null);
Melds optimalMelds;
while (bestNode is not null){
optimalMelds.push(bestNode.cards);
bestNode = bestNode->parent;
}
return optimalMelds;
请注意,possibleMelds 包含所有大小的所有可能融合。例如,对于手 [2-D、3-D、4-D、5-D、5-H、5-S、5-C、10-S、9-C、8-H],@987654331 @ 将包含以下组:
[2-D, 3-D, 4-D],
[3-D, 4-D, 5-D],
[2-D, 3-D, 4-D, 5-D],
[5-D, 5-H, 5-S, 5-C],
[5-H, 5-S, 5-C],
[5-D, 5-S, 5-C],
[5-D, 5-H, 5-C],
[5-D, 5-H, 5-S]