这里有几个算法。您可以非常简单地使用 itertools 对所有可能的组合进行蛮力搜索:
from itertools import product, chain
def get_compatible_solutions(subsolutions):
for sol in product(*subsolutions):
if len(set(chain.from_iterable(sol))) == sum(map(len, sol)):
yield sol
# Test
example = [
[[1, 2, 3], [1, 2, 4], [1, 2, 5], [5, 8]],
[[1, 3], [7, 8], [6, 1]],
[[]],
[[9, 10], [7, 5], [6, 9], [6, 10]]
]
# Get one solution
print(next(get_compatible_solutions(example)))
# ([1, 2, 3], [7, 8], [], [9, 10])
# Get all solutions
print(*get_compatible_solutions(example), sep='\n')
# ([1, 2, 3], [7, 8], [], [9, 10])
# ([1, 2, 3], [7, 8], [], [6, 9])
# ([1, 2, 3], [7, 8], [], [6, 10])
# ([1, 2, 4], [7, 8], [], [9, 10])
# ([1, 2, 4], [7, 8], [], [6, 9])
# ([1, 2, 4], [7, 8], [], [6, 10])
# ([1, 2, 5], [7, 8], [], [9, 10])
# ([1, 2, 5], [7, 8], [], [6, 9])
# ([1, 2, 5], [7, 8], [], [6, 10])
# ([5, 8], [1, 3], [], [9, 10])
# ([5, 8], [1, 3], [], [6, 9])
# ([5, 8], [1, 3], [], [6, 10])
# ([5, 8], [6, 1], [], [9, 10])
另一种可能性是一次进行一行递归搜索。这将探索比笛卡尔积更少的候选解决方案,因为一旦从搜索路径中排除次优解决方案,就不会处理包括它在内的任何组合。
def get_compatible_solutions(subsolutions):
current = [None] * len(subsolutions)
seen = set()
yield from _get_compatible_solutions_rec(subsolutions, current, 0, seen)
def _get_compatible_solutions_rec(subsolutions, current, i, seen):
if i >= len(subsolutions):
yield tuple(current)
else:
for subsol in subsolutions[i]:
if any(s in seen for s in subsol):
continue
seen.update(subsol)
current[i] = subsol
yield from _get_compatible_solutions_rec(subsolutions, current, i + 1, seen)
seen.difference_update(subsol)