Algorithm Gin-Rummy-确定最佳融合的算法
这里也有人问过类似的问题,但在我的问题中,不局限于3号的熔炉,熔炉可以是任何尺寸 在杜松子酒拉米酒中,对于任何特定的一组牌,牌可以分为两组或一组。一组是一组3张或3张以上等级相同的牌(2-D、2-C、2-H或7-D、7-C、7-H、7-S)。跑步是一组3张或3张以上的牌,具有连续的等级和相同的花色(A-D、2-D、3-C或7-C、8-C、9-C、10-C、J-C)。不属于某一组的牌被称为“枯木牌” 我的算法的目标是找到一组特定卡片的最佳融合,这是一个最小化所有死木值总和的算法(数字卡片的值是它们的关联数字,ace的值是1,脸卡片的值是10) 我最初尝试的算法是基于这样一个假设的:对于任何冲突的运行和集合组,要么运行存在,要么集合组存在。在此假设下,该算法只需计算运行值和所有集合值之和,并保留较大值。例如,如果我们有小组 [2-D,3-D,4-D],[2-D,2-C,2-H]和[4-D,4-H,4-S]。运行值之和为2+3+4=9,所有集合值之和为2+2+2+4+4+4=18。在这种情况下,这意味着这两组将保持最佳熔化,不会使用运行(3-D将是枯木) 这一假设适用于规模为3的群体,但对规模较大的群体无效。例如,考虑以下两组: [4-D,5-D,6-D,7-D],[7-D,7-H,7-S] 最佳分组结果是[4-D、5-D、6-D]和[7-D、7-H、7-S]。将保留冲突的集合和运行的一部分。我不知道如何创建一个算法,这不仅仅是暴力 任何帮助或想法都将不胜感激 编辑 我意识到我原来的算法甚至不适用于大小为3的融合。对于以下组:Algorithm Gin-Rummy-确定最佳融合的算法,algorithm,Algorithm,这里也有人问过类似的问题,但在我的问题中,不局限于3号的熔炉,熔炉可以是任何尺寸 在杜松子酒拉米酒中,对于任何特定的一组牌,牌可以分为两组或一组。一组是一组3张或3张以上等级相同的牌(2-D、2-C、2-H或7-D、7-C、7-H、7-S)。跑步是一组3张或3张以上的牌,具有连续的等级和相同的花色(A-D、2-D、3-C或7-C、8-C、9-C、10-C、J-C)。不属于某一组的牌被称为“枯木牌” 我的算法的目标是找到一组特定卡片的最佳融合,这是一个最小化所有死木值总和的算法(数字卡片的值是它们
[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]
[4-D,5-D,6-D],[4-C,5-C,6-C],[6-D,6-C,6-S]
该算法将分别查看这两次运行,并得出结论认为应该删除它们以支持集合,但最佳解决方案是保留两次运行并删除集合
仍在寻求帮助,以创建一个适用于所有边缘情况的算法。我以前的答案被删除,因为我没有真正提供解释,只是提供了一个指向脚本的链接,其中包含了解决此问题的算法。我意识到为什么现在这不适合作为堆栈溢出的答案。以下是我试图给出的完整答案 我在这里展示的算法基于在这里找到的方法:。正如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
,给定一个meld数组和一个meld,该函数将返回一个meld数组,其中只包含与给定meld不冲突的meld
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++中的内存泄漏。如有必要,在使用数据时采取措施释放内存(您可以在此函数中释放不属于最佳树的节点的内存,然后在使用后释放属于最佳树的节点的内存)
最后,可以使用getoptimizemelding
函数如下确定最佳熔接
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;
我之前的答案被删除了,因为我没有真正提供解释,只是提供了一个链接到一个脚本,其中包含了解决这个问题的算法。我意识到为什么现在这不适合作为堆栈溢出的答案。以下是我试图给出的完整答案 我在这里展示的算法基于在这里找到的方法:。正如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
,给定一个meld数组和一个meld,该函数将返回一个meld数组,其中只包含与给定meld不冲突的meld
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++中的内存泄漏。如有必要,在使用数据时采取措施释放内存(您可以在此函数中释放不属于最佳树的节点的内存,然后在使用后释放属于最佳树的节点的内存)
最后,可以使用getoptimizemelding
函数如下确定最佳熔接
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;
这个问题很像“集合覆盖”问题,是NP难问题。因此,找到所有的最大融合(例如通过回溯搜索),然后根据deadwood得分选择最佳融合,这可能是最好的。这个问题很像“集合覆盖”问题,这是NP难问题。因此,找到所有最大的融合(例如通过回溯搜索),然后根据deadwood得分选择最佳融合可能是最好的。