Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm Gin-Rummy-确定最佳融合的算法_Algorithm - Fatal编程技术网

Algorithm Gin-Rummy-确定最佳融合的算法

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)。不属于某一组的牌被称为“枯木牌” 我的算法的目标是找到一组特定卡片的最佳融合,这是一个最小化所有死木值总和的算法(数字卡片的值是它们

这里也有人问过类似的问题,但在我的问题中,不局限于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的融合。对于以下组:

[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得分选择最佳融合可能是最好的。