Если бы вы генерировали все подмножества, вы бы в конечном итоге генерировали 2 n подмножеств для списка длины n . Обычный способ сделать это - перебрать все числа i от 0 до 2 n -1 и использовать биты, установленные в i , чтобы определить, какие элементы находятся в i -ом подмножестве. Это работает, потому что любой элемент либо присутствует, либо отсутствует в каком-либо конкретном подмножестве, поэтому путем перебора всех комбинаций n битов вы перебираете 2 n подмножества.
Например, чтобы сгенерировать подмножества (1, 2, 3), вы должны были бы перебрать числа от 0 до 7:
0 = 000 b & rarr; ()
1 = 001 b & rarr; (1)
2 = 010 b & rarr; (2)
3 = 011 b & rarr; (1, 2)
4 = 100 b & rarr; (3) * * тысяча сорок две
5 = 101 b & rarr; (1, 3)
6 = 110 b & rarr; (2, 3)
7 = 111 b & rarr; (1, 2, 3)
В вашей задаче вы можете сгенерировать каждое подмножество и его дополнение, чтобы получить пару взаимоисключающих подмножеств. Каждая пара будет повторяться, когда вы делаете это, поэтому вам нужно всего лишь повторить до 2 n -1 - 1 и затем остановиться.
1 = 001 b & rarr; (1) + (2, 3)
2 = 010 b & rarr; (2) + (1, 3)
3 = 011 b & rarr; (1, 2) + (3)
Чтобы иметь дело с дублирующимися элементами, вы можете генерировать подмножества индексов списка вместо подмножеств элементов списка. Как и в случае со списком (1, 2, 2, 3), вместо этого создайте подмножества списка (0, 1, 2, 3) и затем используйте эти числа в качестве индексов в списке (1, 2, 2, 3). Добавьте уровень косвенности, в основном.
Вот некоторый код Python, объединяющий все это.
#!/usr/bin/env python
def split_subsets(items):
subsets = set()
for n in xrange(1, 2 ** len(items) / 2):
# Use ith index if ith bit of n is set.
l_indices = [i for i in xrange(0, len(items)) if n & (1 << i) != 0]
# Use the indices NOT present in l_indices.
r_indices = [i for i in xrange(0, len(items)) if i not in l_indices]
# Get the items corresponding to the indices above.
l = tuple(items[i] for i in l_indices)
r = tuple(items[i] for i in r_indices)
# Swap l and r if they are reversed.
if (len(l), l) > (len(r), r):
l, r = r, l
subsets.add((l, r))
# Sort the subset pairs so the left items are in ascending order.
return sorted(subsets, key = lambda (l, r): (len(l), l))
for l, r in split_subsets([1, 2, 2, 3]):
print l, r
Выход:
(1,) (2, 2, 3)
(2,) (1, 2, 3)
(3,) (1, 2, 2)
(1, 2) (2, 3)
(1, 3) (2, 2)