提问者:小点点

如何写一个高效的配对算法?


我需要一种算法的帮助,该算法可以有效地将人们分组成对,并确保以前的配对不会重复。

例如,假设我们有10名候选人;

候选=[0,1,2,3,4,5,6,7,8,9]

假设我们有一个先前匹配的字典,使得每个键值对,即候选人:匹配代表一个候选人和到目前为止它们已经配对的候选人数组;

< code>prev_matches = {0: [6,5,1,2],1: [4,9,0,7],2: [9,8,6,0],3: [5,4,8,9],4: [1,3,9,6],5: [3,0,7,8],6: [0,7,2,4],7: [8,6,5,1],8: [7,2,3,5],9: [2,1,4,3]}

因此,对于Candidate 0,它们首先与Candidate 6配对,在随后的配对轮中,它们与Candidate 5Candidate 1Candidate 2配对。字典中的其他键值对也是如此。

已经有四轮匹配,如< code>prev_matches中所有匹配的长度所示。我如何编写一个算法来创建第五个、第六个...n(最多numberOfCandidates - 1)轮匹配,使候选人没有重复对?

因此,候选人0不能再与候选人6候选人5候选人1候选人2配对。在可能的第五轮匹配之后,我们可以得到我们的prev_matches如下:

prev_matches:{0:[6,5,1,2,3],1:[4,9,0,7,2],2:[9,8,6,0,1],3:[5,4,8,9,0],4:[1,3,9,6,7],5:[3,0,8,8,9],6:[0,7,2,4,8],7:[8,6,5,1],8:[7,2,3,5,8],9:[2,1,4,3,5]}

我尝试了一个简单的解决方案:

def make_match(prev_matches):
    paired_candidates = set()
    for candidate, matches in prev_matches.items():
        i = 0
        while i < 10:
            if i != candidate and i not in matches and i not in paired_candidates and candidate not in paired_candidates:
                prev_matches[candidate].append(i)
                prev_matches[i].append(candidate)
                paired_candidates.add(candidate)
                paired_candidates.add(i)
                break
            i += 1
    return prev_matches

它在第五轮中起作用并返回以下内容:

< code>prev_matches = {0: [6,5,1,2,3],1: [4,9,0,7,2],2: [9,8,6 0,1],3: [5,4,8,9,0],4: [1,3,9,6,5],5: [3,0,7,7,2,4,4],6: [0,7,2,4,8],7: [8,6,5,1,9],8: [7,2,3,5,6],9: [2,1,4,4,3

然而,在第六轮中,它未能发挥作用,因为一些候选人(7 和 8)找不到有效的配对:

prev_matches = {0: [6, 5, 1, 2, 3, 4], 1: [4, 9, 0, 7, 2, 3], 2: [9, 8, 6, 0, 1, 5], 3: [5, 4, 8, 9, 0, 1], 4: [1, 3, 9, 6, 5, 0], 5: [3, 0, 7, 8, 4, 2], 6: [0, 7, 2, 4, 8, 9], 7: [8, 6, 5, 1, 9], 8: [7, 2, 3, 5, 6], 9: [2, 1, 4, 3, 7, 6]}

因此,它既不可靠也不可接受的解决方案。

我正在考虑将其视为回溯问题,这样我将探索所有可能的配对,直到我在第n轮后找到完全可接受且有效的解决方案。但这里的问题是如何使其高效工作。

我将感激我能得到的任何帮助。


共1个答案

匿名用户

如果你从一开始就负责比赛,那么最简单的解决方案就是根据循环赛组织配对。

如果您无法控制第一轮比赛的配对,并且必须组织以下比赛,则可以使用模块networkx计算图表中的最大匹配:

from networkx import Graph
from networkx.algorithms.matching import max_weight_matching, is_perfect_matching

def next_rounds(candidates, prev_matches):
    G = Graph()
    G.add_nodes_from(candidates)
    G.add_edges_from((u,v) for u,p in prev_matches.items() for v in candidates.difference(p).difference({u}))
    m = max_weight_matching(G)
    while is_perfect_matching(G, m):
        yield m
        G.remove_edges_from(m)
        m = max_weight_matching(G)

for r in next_rounds({0,1,2,3,4,5,6,7,8,9},
                     {0: [6, 5, 1, 2], 1: [4, 9, 0, 7], 2: [9, 8, 6, 0], 3: [5, 4, 8, 9], 4: [1, 3, 9, 6],  5: [3, 0, 7, 8], 6: [0, 7, 2, 4], 7: [8, 6, 5, 1], 8: [7, 2, 3, 5], 9: [2, 1, 4, 3]}):
    print(r)

输出:

{(2, 7), (8, 1), (0, 9), (4, 5), (3, 6)}
{(2, 4), (3, 7), (8, 0), (9, 5), (1, 6)}
{(0, 7), (8, 4), (1, 5), (9, 6), (2, 3)}
{(9, 7), (0, 4), (8, 6), (2, 5), (1, 3)}
{(1, 2), (0, 3), (8, 9), (5, 6), (4, 7)}