Generowanie wszystkich podzbiorów

Jeśli chcemy zastosować pewną operację do każdego podzbioru danego zbioru, wtedy musimy w odpowiedni sposób wygenerować te podzbiory. Nie ma możliwości, aby wykonać to w czasie wielomianowym, gdyż liczba podzbiorów zbioru N-elementowego wynosi 2N. (Wliczamy tu także podzbiór pusty i podzbiór zawierający wszystkie elementy danego zbioru.)

Oznaczmy nasz zbiór przez A, a jego liczbę elementów przez N. Elementy zbioru A ponumerujemy i oznaczymy przez Ai, i = 0, 1, …, N-1. Każdy jego podzbiór można jednoznacznie scharakteryzować ciągiem N bitów: jeśli bit na pozycji k-tej jest ustawiony, wtedy k-ty element zbioru A należy do tego podzbioru. Zatem każdy podzbiór posiada unikalną sygnaturę w postaci liczby całkowitej z przedziału 〈0; 2N-1〉:

subset01.gif

Przykład dla N = 7
sygnatura: (0101001)2 = (9)10

Do podzbioru należą elementy: A0, A3, A5

Algorytm, który wybiera elementy zbioru A w oparciu o sygnaturę S ma postać:

subset(S)
   list = {Ø}
   mask = 1
   for i=0 to N-1 do
      if mask & S > 0
         put(list, A[i])
      mask = mask << 1
   return list

Operatory & oraz << to operatory bitowe (jak w C++), zaś funkcja put powoduje dołączenie kolejnego elementu do listy.

Wszystkie podzbiory generujemy (i ewentualnie przetwarzamy) przez wykonanie pętli:

M = (1<<N)-1
for S=0 to M do
   process(subset(S))

Na przykład dla N=7 i zbioru A={1,2,3,4,5,6,7} otrzymamy kolejno następujące podzbiory:

{Ø}
1
2
1 2
3
1 3
2 3
1 2 3
4
1 4
2 4
1 2 4
3 4
1 3 4
2 3 4
1 2 3 4

5
1 5
2 5
1 2 5
3 5
1 3 5
2 3 5
1 2 3 5
4 5
1 4 5
2 4 5
1 2 4 5
3 4 5
1 3 4 5
2 3 4 5
1 2 3 4 5

6
1 6
2 6
1 2 6
3 6
1 3 6
2 3 6
1 2 3 6
4 6
1 4 6
2 4 6
1 2 4 6
3 4 6
1 3 4 6
2 3 4 6
1 2 3 4 6

5 6
1 5 6
2 5 6
1 2 5 6
3 5 6
1 3 5 6
2 3 5 6
1 2 3 5 6
4 5 6
1 4 5 6
2 4 5 6
1 2 4 5 6
3 4 5 6
1 3 4 5 6
2 3 4 5 6
1 2 3 4 5 6

7
1 7
2 7
1 2 7
3 7
1 3 7
2 3 7
1 2 3 7
4 7
1 4 7
2 4 7
1 2 4 7
3 4 7
1 3 4 7
2 3 4 7
1 2 3 4 7

5 7
1 5 7
2 5 7
1 2 5 7
3 5 7
1 3 5 7
2 3 5 7
1 2 3 5 7
4 5 7
1 4 5 7
2 4 5 7
1 2 4 5 7
3 4 5 7
1 3 4 5 7
2 3 4 5 7
1 2 3 4 5 7

6 7
1 6 7
2 6 7
1 2 6 7
3 6 7
1 3 6 7
2 3 6 7
1 2 3 6 7
4 6 7
1 4 6 7
2 4 6 7
1 2 4 6 7
3 4 6 7
1 3 4 6 7
2 3 4 6 7
1 2 3 4 6 7

5 6 7
1 5 6 7
2 5 6 7
1 2 5 6 7
3 5 6 7
1 3 5 6 7
2 3 5 6 7
1 2 3 5 6 7
4 5 6 7
1 4 5 6 7
2 4 5 6 7
1 2 4 5 6 7
3 4 5 6 7
1 3 4 5 6 7
2 3 4 5 6 7
1 2 3 4 5 6 7



Powrót do Algorytmy wykładnicze
O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-ShareAlike 3.0 License