【问题标题】:Find longest combination of non-overlapping pairs找到最长的非重叠对组合
【发布时间】:2022-08-21 03:50:05
【问题描述】:

我需要找到可以从对列表中组成的最长对组合的长度,没有任何共同元素。

例如下面的对列表:

[(A, B), (A, D), (B, C), (B, D), (C, D)]

会有这些组合:

[(A, B), (C, D)] 
[(A, D), (B, C)]
[(B, D)]

因此最长的组合长度为 2 对。

这需要能够处理多达数千对,因此在每个可能的长度上生成所有可能的对组合并检查重叠将不起作用。

但是,所有对中唯一元素的总数上限为 100,因此可能遇到的最长可能组合为 50 对。

有没有一种有效的方法来做到这一点?

  • 不重叠,因为没有一个元组共享任何元素?
  • 是的,这是我正在寻找的明确声明
  • 听起来像一个递归作业问题,给我一秒钟尝试为你解决一些问题
  • 我很好奇我们可以在这里使用贪婪的方法吗?
  • @funnydman 我不这么认为,考虑到下一个选择完全取决于我们已经选择的内容,您必须考虑过去的选择来解决这个问题

标签: python combinations combinatorics


【解决方案1】:

好吧,这就是我所拥有的,也许不是最好的,但它的东西

所以 Combo 初始化任何 2 对,并将其与数组的其余部分一起提供给 Combine 尚未检查

Combine 接受一个剩余数组,当前组合和一个已使用元素的列表,然后检查每个可能的组合,如果剩余数组中的检查元组在已使用列表中有任何元素,则跳过它,如果没有,则添加它到组合并将其传递给进一步递归的组合,直到它可以

arr = [('A', 'B'), ('A', 'D'), ('B', 'C'), ('B', 'D'), ('E', 'D'), ("A",'F'),('J','K'),('M','K'),('K','D'),('B','F')]

def Combo(arr):

    combos = []

    for i, tup1 in enumerate(arr):
        combo = [tup1]
        used = [tup1[0], tup1[1]]
        for j, tup2 in enumerate(arr[i:]):
            if (tup2[0] in used) or (tup2[1] in used):
                continue
            else:
                for el in tup2:
                    used.append(el) 
                combo.append(tup2)
                combo=Combine(arr[j:], combo, used)
            combos.append(combo)
    return combos


def Combine(arr, combo, used):
    if arr==[]:
        return combo
    for i, tup in enumerate(arr):
        unique = True
        for el in tup:
            if el in used:
                unique = False
                continue
        if unique:
            combo.append(tup)
            for el in tup:
                used.append(el)
            return Combine(arr[i:], combo, used)
        
    return combo


Combo(arr)

输出

[[('A', 'B'), ('E', 'D'), ('J', 'K')],
[('A', 'D'), ('B', 'C'), ('J', 'K')],
[('B', 'C'), ('E', 'D'), ('A', 'F'), ('J', 'K')],
[('B', 'D'), ('A', 'F'), ('J', 'K')],
[('E', 'D'), ('A', 'F'), ('B', 'C'), ('J', 'K')],
[('A', 'F'), ('J', 'K'), ('B', 'C'), ('E', 'D')],
[('J', 'K'), ('B', 'F'), ('E', 'D')],
[('M', 'K'), ('B', 'F'), ('E', 'D')],
[('K', 'D'), ('B', 'F')]]

据我所知,这应该为您提供列表中的每个独特组合

【讨论】:

  • 这是错误的,它没有给出每一个独特的组合,让我修改一下
【解决方案2】:

重新表述这个问题,我们想要找到最大的一组非重叠元素对。可能不是最好的解决方案,但应该可以:

def process(pairs):
    output = {}
    max_length = 0
    for i in range(len(pairs)):
        curr = 1
        output[pairs[i]] = set(pairs[i])
        rest = pairs[:i] + pairs[i + 1:]
        for j in range(len(rest)):
            subset = output[pairs[i]] | set(rest[j])
            if len(subset) == len(output[pairs[i]]) + 2:
                curr += 1
                output[pairs[i]] = subset
            max_length = max(curr, max_length)
    return max_length

我们用当前对填充我们的初始集合,然后如果下一个对的元素没有出现在当前集合中,我们扩展它。我们继续这个过程,直到我们检查了所有剩余的对。我使用此功能进行测试:

import random, timeit

def get_random_pairs(num):
    return [(random.choice(string.ascii_uppercase), random.choice(string.ascii_uppercase)) for _ in range(num)]

print(timeit.timeit('process(pairs)', number=5, setup="from __main__ import process,get_random_pairs; pairs = get_random_pairs(3000)")/5)

在我的机器上(Intel i7-9750H (12) @ 4.500GHz)处理 3000 对大约需要 5-6 秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    • 2016-06-03
    • 1970-01-01
    • 2018-01-19
    • 1970-01-01
    • 2021-03-12
    • 2020-04-03
    相关资源
    最近更新 更多