2012-12-21 16 views
5

Mam tablicę, a jej długość to X. Każdy element tablicy ma zakres 1 .. L. Chcę efektywnie iterować poprzez wszystkie kombinacje tablic, które mają sumę L.Jak skutecznie iterować kombinacje tablic ze stałą sumą?

Prawidłowe rozwiązania dla L = 4, a X = 2

1 3 
3 1 
2 2 

Prawidłowe rozwiązania dla L = 5 i X = 3

1 1 3 
1 3 1 
3 1 1 
1 2 2 
2 1 2 
2 2 1 

Naiwne wykonania jest (nic dziwnego) zbyt wolno dla mojego problemu (X ma maksymalnie 8 w moim przypadku, a L ma nawet 128).

Czy ktoś może mi powiedzieć, w jaki sposób jest wywoływany ten problem lub gdzie znaleźć szybki algorytm dla problemu?

Dzięki!

+2

Wydaje mi się, że szukasz * całkowite partycje * 'L' o długości' X'. –

+2

Nie możesz tego zrobić * sprawnie * (w literaturze, wydajnie = wielomianowo). Istnieje wykładnicza liczba rozwiązań, a do iteracji wszystkich wymaga wykładniczy czas. – amit

+0

To byłby świetny problem z eulerem projektu =) –

Odpowiedz

8

Jeśli dobrze rozumiem, masz podane dwa numery 1 ≤ XL i chcesz wygenerować wszystkie sekwencje liczb całkowitych dodatnich o długości X że suma L.

(Uwaga: to jest podobne do integer partition problem, ale nie to samo, ponieważ uważamy, że 1,2,2 jest inną sekwencją niż 2,1,2, natomiast w przypadku problemu z partycją całkowitą ignorujemy kolejność, tak, że są one uważane za takie same partycja)

sekwencje którego szukasz odpowiadają combinations z X. - 1 pozycji z L - 1. w przypadku, jeśli stawiamy numery 1 do L - 1 w kolejności i wybierz X - 1 z nich, a następnie długości przerw między wybranymi liczby są liczbami całkowitymi dodatnimi, które sumują się do L.

Na przykład załóżmy, że L jest 16 i X jest 5. Następnie wybierz 4 numery od 1 do 15 włącznie:

the four numbers 3, 7, 8, and 14 are chosen from 1 to 15

Dodaj 0 na początku i na końcu 16 i interwały:

intervals 0–3, 3–7, 7–8, 8–14 and 14–16

i 3 + 4 + 1 + 6 + 2 = 16 według potrzeby.

Więc generate the combinations z X - 1 elementów z L - 1, a dla każdego z nich, przekształcić go na partycji poprzez znalezienie interwały. Na przykład w Pythonie można napisać:

from itertools import combinations 

def partitions(n, t): 
    """ 
    Generate the sequences of `n` positive integers that sum to `t`. 
    """ 
    assert(1 <= n <= t) 
    def intervals(c): 
     last = 0 
     for i in c: 
      yield i - last 
      last = i 
     yield t - last 
    for c in combinations(range(1, t), n - 1): 
     yield tuple(intervals(c)) 

>>> list(partitions(2, 4)) 
[(1, 3), (2, 2), (3, 1)] 
>>> list(partitions(3, 5)) 
[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)] 

Istnieje (L - 1)!/(X - 1)! (L - X)!kombinacje X - 1 pozycji z L - 1, więc środowisko wykonawcze tego algorytmu (i rozmiar jego wyjścia) jest wykładnicze w L. Jeśli jednak nie policzysz wyjścia, potrzebujesz tylko przestrzeni O (L).

Z L = 128 i X = 8, istnieją 89,356,415,775 przegródki, więc zajmie to trochę czasu na wyjście nimi wszystkimi!

(Może jeśli wyjaśnić, dlaczego obliczanie tych partycji, możemy być w stanie zaproponować jakiś sposób spełnienia wymagań, bez konieczności rzeczywiście produkują je wszystkie.)

+0

Myślę, że ta implementacja mogłaby zostać zoptymalizowana, gdybyś przestawił "odstępy" z pętli i przekazał "c" jako parametr wejściowy - W ten sposób nie tworzysz nowego funkcja dla każdej kombinacji. – mgilson

+0

@mgilson: Przeniosłem definicję funkcji z pętli, abyś był szczęśliwy. Jednak ten rodzaj optymalizacji wydaje się bezcelowy w obliczu wykładniczego działania środowiska wykonawczego programu. Byłoby lepiej dowiedzieć się, jak w ogóle unikać obliczania tych partycji. –

+0

Zgadzam się - to bardzo mała optymalizacja w obliczu prawie beznadziejnego zadania. Ale jeśli mamy zamiar napisać taką implementację, równie dobrze mógłby być dobry :-) – mgilson

Powiązane problemy