如何在这些阵列中找到可能的最大匹配量?

时间:2015-02-22 04:16:19

标签: python arrays python-2.7

我喜欢编程挑战并尝试解决它们,然而,这个让我感到有点难过,我真的可以在正确的方向上使用一个点。

有一组数字,1到N代表女性,N + 1到2N代表男性。 (因此,如果N = 5那么这意味着1,2,3,4,5 =女性和6,7,8,9,10 =男性。)我试图找到可能的最大匹配量。虽然这是一个问题,女性数字是挑剔的,只会与他们的数字配对。所以它看起来像这样:

19
1: 25
2: 20 25 28
3: 27 32 37
4: 22
5: 32 38
6: 32 34 35
7: 22 34 37
8: 30 35 38
9: 20 23
10: 24 29
11: 29 32
12: 23 26 31
13: 21 25 34
14: 21 27
15: 20
16: 23 31 38
17: 22 27 28
18: 35
19: 24 25

所以“#:”是女孩的地方,你会说女孩#1只会和第25个人配对。同样,女孩#2只会与男性#20,25或28对。

我对此的解决方案是将每一行放入一个数组中,然后再创建一个已使用的空数组。我从女孩开始,她们只会与一个人配对并给他们配对。然后我去找那些只与2人一组中的人配对的女孩。最后是3.

这种方法效果不错,但是,这意味着有些人在可能的情况下没有配对,因此,由于它的先到先得的性质,我的最大配对数量未达到。< / p>

使用上面的例子,我得到16个中的16个(最多可能是17个),其中3个未配对的女孩是#13,17和19。

这是我目前的代码:

def findPairs(women):
    pairs = []
    taken = []
    for woman in range(women):
        data = raw_input()

        #Remove the "#: " in each line and format numbers into ['1','2','3']
        data = (data[len(str(woman))+2:]).split()
        pairs.append(data)

    for entry in pairs:
        if len(entry) == 1:
            if entry[0] not in taken:
                taken.append(entry[0])
            else:
                print("No match for " + str(entry))

    for entry in pairs:
        if len(entry) == 2:
            if entry[0] not in taken:
                taken.append(entry[0])
            elif entry[1] not in taken:
                taken.append(entry[1])
            else:
                print("No match for " + str(entry))

    for entry in pairs:
        if len(entry) == 3:
            if entry[0] not in taken:
                taken.append(entry[0])
            elif entry[1] not in taken:
                taken.append(entry[1])
            elif entry[2] not in taken:
                taken.append(entry[2])
            else:
                print("No match for " + str(entry))

    print(len(taken))
findPairs(input())

有没有人知道如何更好地优化我的配对匹配,以便我可以达到最大配对? (最好是一种可以扩展的方式,找到一种黑客方式来找到这些19的答案,如果它不适用于50个女孩的不同组合,那就没有太大的收获。但是可以假设格式很好将保持不变(即:每行最多3个人,更大到更大的顺序等等。)虽然能够使其尽可能地扩展是很酷的,但除了这个问题之外还有其他问题。 )

2 个答案:

答案 0 :(得分:3)

以下是一个未经优化的实现,用于查找迭代所有不匹配女性的maximum-matching in a bipartite graph,并尝试通过将每个女性与其中一位候选人配对来尝试更改当前匹配,如下所示:

  • 如果有&#34;免费&#34;候选人 - 将匹配添加到图表
  • 如果所有候选人已配对,&#34;取消配对&#34;其中一个和他匹配,然后开始一个迭代的过程,去找那个男人已经配对的女人,将她标记为&#34;无与伦比的&#34;并递归调用。

我将这个过程命名为#34;放松&#34;因为它有点提醒Dijkstra's algorithm中的递归放松步骤。

以下是代码:


import random

def read_file():
    res = {}
    start = True
    with open('pairs.txt', 'r') as f:
        for line in f.readlines():
            if start:
                start = False
                continue
            woman, matches = line.strip().split(': ')
            woman = int(woman)
            matches = map(int, matches.split(' '))
            res[woman] = matches
    return res


def build_random_match(graph):
    edges = {}
    for woman in graph:
        for man in graph[woman]:
            if already_in_edges(man, edges):
                continue
            else:
                edges[woman] = man
                break
    return edges


def already_in_edges(man, edges):
    for woman in edges:
        if edges[woman] == man:
            return True
    else:
        return False


def get_unmatched_women(match, graph):
    return  [woman for woman in graph.keys() if woman not in match.keys()]


def not_in_match(man, match):
    for woman in match:
        if match[woman] == man:
            return False
    else:
        return True


def find_unmatched_man(graph, match, woman):    
    potentials = graph[woman]
    for man in potentials:
        if not_in_match(man, match):
            return man
    else:
        return False


def remove_man_from_match(man, unmatched_woman, match, graph):  
    # find the woman that this man is currently matched with
    # and cancel this matching
    for woman in match:
        if match[woman] == man:
            match_to_del = woman
            break   
    del match[match_to_del]
    # also remove the man from the orig woman (graph) 
    # to prevent infinite loop
    men = graph[unmatched_woman]
    men.remove(man)
    graph[unmatched_woman] = men

    return match_to_del


def relax(unmatched_woman, match, graph):   
    unmatched_man = find_unmatched_man(graph, match, unmatched_woman)
    if unmatched_man:
        match[unmatched_woman] = unmatched_man      
    elif len(graph[unmatched_woman]) == 0:
        return match
    else:
        # grab one of the possible matchings randomly
        rand_index = random.randint(0, len(graph[unmatched_woman])-1)
        man = graph[unmatched_woman][rand_index]
        new_unmatched_woman = remove_man_from_match(man, unmatched_woman, match, graph)
        match[unmatched_woman] = man
        match = relax(new_unmatched_woman, match, graph)

    return match


def improve_match(match, graph):
    if len(match) == len(graph):
        return match

    unmatched_women = get_unmatched_women(match, graph) 
    for woman in unmatched_women:
        copy_graph = graph.copy()
        suggested = relax(woman, match, copy_graph)
        if len(suggested) > len(match):
            return suggested
        else:
            suggested = match
    else:
        return suggested


def main():
    graph = read_file()
    match = build_random_match(graph)   
    if len(match) == len(graph):
        print 'Got a perfect match:', match
    else:
        match_size = 0
        while match_size < len(match):
            match_size = len(match)
            match = improve_match(match, graph)

    return match

if __name__ == '__main__':
    res = main()    
    print "Size of match:", len(res)
    print "Match:", res

输出:

Size of match: 17
Match: {2: 28, 3: 32, 4: 22, 5: 38, 6: 34, 7: 37, 8: 30, 9: 23, 10: 24, 11: 29, 12: 26, 13: 21, 15: 20, 16: 31, 17: 27, 18: 35, 19: 25}

答案 1 :(得分:0)

我不是Python开发人员,但这是我解决问题的方式。

将数据作为列表列表引入。使用女孩的数量作为指标。即女孩1是索引0,在该索引中存储人员列表。为数据创建一个巨大的列表列表。

遍历列表列表,找到女孩与一个人匹配的单场比赛。将单个对战(人)存储在列表中以进行迭代。然后遍历列表列表,从列表列表中删除单个匹配人员。然后重新开始。您的目标是将列表缩减为单个元素,并跟踪列表中的位置。