Как генерировать все перестановки multiset?
мульти-набор-это набор, в котором все элементы не могут быть уникальными.Как перечислить все возможные перестановки между элементами набора?
4 ответов
генерирование всех возможных перестановок, а затем отбрасывание повторяющихся очень неэффективно. Существуют различные алгоритмы для непосредственного создания перестановок мультисета в лексикографическом порядке или другом порядке. Алгоритм такаоки-хороший пример, но, вероятно, алгоритм Аарона Уильямса лучше
http://webhome.csc.uvic.ca~Харон / CoolMulti.pdf
кроме того, он был реализован в пакете R "multicool".
кстати, если вы просто хотите общее количество различных перестановок, ответ-многомерный коэффициент: например, если у вас есть, скажем, n_a элементы 'a', n_b элементы 'b', n_c элементы 'c', общее число различных перестановок (n_a+n_b+n_c)!/(n_a!n_b!n_c!)
существуют алгоритмы O(1) (на перестановку) для генерации многосетевых перестановок, например, от Takaoka (с реализацией)
Это мой перевод алгоритма многосетевых перестановок Takaoka в Python (доступен здесь и в repl.это):
def msp(items):
'''Yield the permutations of `items` where items is either a list
of integers representing the actual items or a list of hashable items.
The output are the unique permutations of the items given as a list
of integers 0, ..., n-1 that represent the n unique elements in
`items`.
Examples
========
>>> for i in msp('xoxox'):
... print(i)
[1, 1, 1, 0, 0]
[0, 1, 1, 1, 0]
[1, 0, 1, 1, 0]
[1, 1, 0, 1, 0]
[0, 1, 1, 0, 1]
[1, 0, 1, 0, 1]
[0, 1, 0, 1, 1]
[0, 0, 1, 1, 1]
[1, 0, 0, 1, 1]
[1, 1, 0, 0, 1]
Reference: "An O(1) Time Algorithm for Generating Multiset Permutations", Tadao Takaoka
https://pdfs.semanticscholar.org/83b2/6f222e8648a7a0599309a40af21837a0264b.pdf
'''
def visit(head):
(rv, j) = ([], head)
for i in range(N):
(dat, j) = E[j]
rv.append(dat)
return rv
u = list(set(items))
E = list(reversed(sorted([u.index(i) for i in items])))
N = len(E)
# put E into linked-list format
(val, nxt) = (0, 1)
for i in range(N):
E[i] = [E[i], i + 1]
E[-1][nxt] = None
head = 0
afteri = N - 1
i = afteri - 1
yield visit(head)
while E[afteri][nxt] is not None or E[afteri][val] < E[head][val]:
j = E[afteri][nxt] # added to algorithm for clarity
if j is not None and E[i][val] >= E[j][val]:
beforek = afteri
else:
beforek = i
k = E[beforek][nxt]
E[beforek][nxt] = E[k][nxt]
E[k][nxt] = head
if E[k][val] < E[head][val]:
i = k
afteri = E[i][nxt]
head = k
yield visit(head)
вы можете уменьшить свою проблему, чтобы перечислить все перестановки списка. Алгоритм генерации типовых перестановок принимает список и не проверяет, равны ли элементы. Поэтому вам нужно только сгенерировать список из вашего мультисета и передать его алгоритму генерации перестановок.
например, у вас есть multiset {1,2,2}.
вы преобразуете его в список [1,2,2].
и генерировать все перестановки, например, в python:
import itertools as it
for i in it.permutations([1,2,2]):
print i
и вы получите на выходе
(1, 2, 2)
(1, 2, 2)
(2, 1, 2)
(2, 2, 1)
(2, 1, 2)
(2, 2, 1)
проблема в том, что вы получаете некоторые перестановки неоднократно. Простым решением было бы просто отфильтровать их:
import itertools as it
permset=set([i for i in it.permutations([1,2,2])])
for x in permset:
print x
выход:
(1, 2, 2)
(2, 2, 1)
(2, 1, 2)