Daję ci listę wektorów bitowych o szerokości . Twoim celem jest zwrócenie dwóch wektorów bitowych z listy, które nie mają wspólnych 1, lub zgłoszenie, że taka para nie istnieje.n
Na przykład, jeśli dam ci wówczas jedynym rozwiązaniem jest . Alternatywnie, wejście nie ma rozwiązania. Każda lista zawierająca całkowicie zerowy bitvector i inny element ma trywialne rozwiązanie .[ 00110 , 01100 , 11000 ]
Oto nieco trudniejszy przykład, bez rozwiązania (każdy wiersz jest nieco wektorem, czarne kwadraty to 1s, a białe kwadraty to 0s):
■ ■ ■ ■ □ □ □ □ □ □ □ □ □
■ □ □ □ ■ ■ ■ □ □ □ □ □ □
■ □ □ □ □ □ □ ■ ■ ■ □ □ □
■ □ □ □ □ □ □ □ □ □ ■ ■ ■
□ ■ □ □ □ ■ □ □ □ ■ ■ □ □
□ ■ □ □ ■ □ □ □ ■ □ □ □ ■
□ ■ □ □ □ □ ■ ■ □ □ □ ■ □ <-- All row pairs share a black square
□ □ ■ □ □ □ ■ □ ■ □ ■ □ □
□ □ ■ □ □ ■ □ ■ □ □ □ □ ■
□ □ ■ □ ■ □ □ □ □ ■ □ ■ □
□ □ □ ■ ■ □ □ ■ □ □ ■ □ □
□ □ □ ■ □ □ ■ □ □ ■ □ □ ■
□ □ □ ■ □ ■ □ □ ■ □ □ ■ □
Jak skutecznie można znaleźć dwa nienakładające się wektory bitowe lub pokazać, że nie istnieją?
Naiwnym algorytmem, w którym po prostu porównujesz każdą możliwą parę, jest . Czy można to zrobić lepiej?O ( n 2 k )
źródło
Odpowiedzi:
Rozgrzewanie: losowe wektory bitowe
Jako rozgrzewkę możemy zacząć od przypadku, w którym każdy bitvector jest wybierany losowo równomiernie. Potem okazuje się, że problem można rozwiązać w czasie (a dokładniej można zastąpić ).O ( N : 1,6 min ( k , lg n ) ) 1,6 lg 3O(n1.6min(k,lgn)) 1.6 lg3
Rozważymy następujący dwuczęściowy wariant problemu:
Podane zestawy z bitvectors określić, gdzie istnieje nienakładające się para .S , T ⊆ { 0 , 1 } k s ∈ S , t ∈ TS,T⊆{0,1}k s∈S,t∈T
Podstawową techniką rozwiązania tego jest dzielenie i podbijanie. Oto algorytm czasowy przy użyciu funkcji dziel i zwycięż:O ( n 1,6 k )O(n1.6k)
Podziel i podstawie pierwszej pozycji bitu. Innymi słowy, formularz , , , .S T S 0 = { s ∈ S : s 0 = 0 } S 1 = { s ∈ S : s 0 = 1 } T 0 = { t ∈ T : t 0 = 0 } T 1 = { t ∈ T : t 0 = 1 }S T S0={s∈S:s0=0} S1={s∈S:s0=1} T0={t∈T:t0=0} T1={t∈T:t0=1}
Teraz rekurencyjnie szukaj pary nienakładającej się z , z oraz z . Jeśli jakieś wywołanie rekurencyjne znajdzie parę, która się nie nakłada, wyślij ją, w przeciwnym razie wyślij „Nie ma pary nakładających się”.S 0 , T 0 S 0 , T 1 T 1 , S 0S0,T0 S0,T1 T1,S0
Ponieważ wszystkie wektory bitowe są wybierane losowo, możemy spodziewać się i . Mamy więc trzy rekurencyjne wywołania i zmniejszyliśmy rozmiar problemu dwa razy (oba zestawy są zmniejszone dwa razy). Po jeden z dwóch zestawów ma rozmiar 1, a problem można rozwiązać w czasie liniowym. Otrzymujemy relację powtarzalności wzdłuż linii , których rozwiązaniem jest . Uwzględniając czas wykonywania dokładniej w przypadku dwóch zestawów, widzimy, że czas działania wynosi .| S b | ≈ | S | / 2 | T b | ≈ | T | / 2 lg min ( | S | , | T | ) T ( n ) = 3 T ( n / 2 ) + O ( n k ) T ( n ) = O ( n 1,6 k ) O|Sb|≈|S|/2 |Tb|≈|T|/2 lgmin(|S|,|T|) T(n)=3T(n/2)+O(nk) T(n)=O(n1.6k) ( min ( | S | , | T | ) 0,6 maks. ( | S | , | T | ) k )O(min(|S|,|T|)0.6max(|S|,|T|)k)
Można to jeszcze poprawić, zauważając, że jeśli , prawdopodobieństwo istnienia pary, która się nie pokrywa, jest wykładniczo małe. W szczególności, jeśli są dwoma losowymi wektorami, prawdopodobieństwo, że się nie pokrywają, wynosi . Jeśli , istnieje takich par, więc przez związanie, prawdopodobieństwo istnienia pary, która się nie nakłada, wynosi najwyżej . Kiedy , to . Tak więc, jako etap wstępnego przetwarzania, jeślik ≥ 2,5 lg n + 100 x , r ( 3 / 4 ), k | S | = | T | = N n 2 n 2 ( 3 / 4 ) k k ≥ 2,5 lg n + 100k≥2.5lgn+100 x,y (3/4)k |S|=|T|=n n2 n2(3/4)k k≥2.5lgn+100 ≤ 1 / 2 100 K ≥ 2,5 lg n + 100≤1/2100 k≥2.5lgn+100 , wówczas możemy natychmiast zwrócić „Nie ma pary nienakładającej się” (prawdopodobieństwo, że jest to niepoprawne, jest pomijalnie małe), w przeciwnym razie uruchomimy powyższy algorytm.
W ten sposób osiągamy czas działania (lub dla wariantu dwóch zestawów zaproponowanego powyżej), dla specjalnego przypadku, w którym bitwektory są wybierane równomiernie losowo.O ( n 1,6 min ( k , lg n ) ) O ( min ( | S | , | T | ) 0,6 maks. ( | S | , | T | ) min ( k , lg n ) )O(n1.6min(k,lgn)) O(min(|S|,|T|)0.6max(|S|,|T|)min(k,lgn))
Oczywiście nie jest to najgorsza analiza. Losowe wektory bitowe są znacznie łatwiejsze niż najgorszy przypadek - ale traktujmy to jako rozgrzewkę, aby uzyskać kilka pomysłów, które być może moglibyśmy zastosować w przypadku ogólnym.
Lekcje z rozgrzewki
Możemy nauczyć się kilku lekcji z powyższej rozgrzewki. Po pierwsze, pomocna jest funkcja dziel i zwyciężaj (dzielenie na pozycję bitową). Po drugie, chcesz podzielić się na pozycji bitowej z jak największą liczbą w tej pozycji; im więcej , tym mniejsze zmniejszenie wielkości podproblemu.1 01 0
Po trzecie, sugeruje to, że problem staje się trudniejszy, gdy gęstość jest mniejsza - jeśli wśród bitvektorów jest bardzo niewiele (są to w większości ), problem wygląda dość trudny, ponieważ każdy podział zmniejsza się wielkość podproblemów trochę. Zdefiniuj więc gęstość jako ułamek bitów, które są (tj. Spośród wszystkich bitów ), a gęstość pozycji bitu aby była ułamkiem wektorów bitowych, które są w pozycji .1 1 0 Δ 1 n k i 1 i1 1 0 Δ 1 nk i 1 i
Obsługa bardzo niskiej gęstości
W kolejnym kroku możemy zastanawiać się, co się stanie, jeśli gęstość będzie wyjątkowo mała. Okazuje się, że jeśli gęstość w każdej pozycji bitowej jest mniejsza niż , gwarantujemy, że istnieje para nie nakładająca się: istnieje (niekonstruktywny) argument istnienia wskazujący, że niektóre nie nakładające się para musi istnieć. To nie pomaga nam go znaleźć, ale przynajmniej wiemy, że istnieje.1 / √k1/k−−√
Dlaczego tak jest? Powiedzmy, że para wektorów bitowych jest objęta pozycją bitu jeśli . Zauważ, że każda para nakładających się wektorów bitowych musi być zakryta przez jakąś pozycję bitu. Teraz, jeśli naprawimy określoną pozycję bitu , liczba par, które mogą być objęte tą pozycją bitu, wynosi co najwyżej . Podsumowując wszystkie pozycji bitów, stwierdzamy, że łączna liczba par objętych pewną pozycją bitową wynosix , y i x I = Y i = 1 i ( n Δ ( I ) )x,y i xi=yi=1 i 2 < n 2 / k k < n 2(nΔ(i))2<n2/k k <n2 . Oznacza to, że musi istnieć para, która nie jest objęta żadną pozycją bitową, co oznacza, że ta para się nie nakłada. Jeśli więc gęstość jest wystarczająco niska w każdej pozycji bitowej, z pewnością istnieje para, która się nie nakłada.
Jednak nie mogę zidentyfikować szybkiego algorytmu, aby znaleźć taką nie nakładającą się parę w tych reżimach, nawet jeśli jedna z nich istnieje. Nie widzę od razu żadnych technik, które zapewniłyby czas działania zależny od kwadratury od . Jest to więc miły szczególny przypadek, na którym można się skoncentrować, jeśli chcesz poświęcić trochę czasu na przemyślenie tego problemu.nn
W kierunku algorytmu ogólnego przypadku
W ogólnym przypadku naturalna heurystyka wydaje się być: wybierz pozycję bitu z największą liczbą (tj. O największej gęstości) i podziel na nią. Innymi słowy:i 1i 1
Znajdź pozycję bitową która maksymalizuje .i Δ ( i )i Δ(i)
Podział i podstawie pozycji bitu . Innymi słowy, formularz , , , .S T i S 0 = { s ∈ S : s i = 0 } S 1 = { s ∈ S : s i = 1 } T 0 = { t ∈ T : t i = 0 } T 1 = { t ∈ T : t i = 1 }S T i S0={s∈S:si=0} S1={s∈S:si=1} T0={t∈T:ti=0} T1={t∈T:ti=1}
Teraz rekurencyjnie szukaj pary nienakładającej się z , z oraz z . Jeśli jakieś wywołanie rekurencyjne znajdzie parę, która się nie nakłada, wyślij ją, w przeciwnym razie wyślij „Nie ma pary nakładających się”.S 0 , T 0 S 0 , T 1 T 1 , S 0S0,T0 S0,T1 T1,S0
Wyzwanie polega na analizie jego wydajności w najgorszym przypadku.
Załóżmy, że jako krok przetwarzania wstępnego najpierw obliczamy gęstość każdej pozycji bitu. Ponadto, jeśli dla każdego , przyjmijmy, że krok wstępnego przetwarzania daje wynik „Istnieje nakładająca się para” (zdaję sobie sprawę, że nie pokazuje to przykładu nakładającej się pary, ale odłóżmy to na bok jako osobne wyzwanie). Wszystko to można zrobić w czasie . Informacje o zagęszczeniu mogą być skutecznie utrzymywane, gdy wykonujemy połączenia rekurencyjne; nie będzie dominującym czynnikiem wpływającym na czas działania.Δ ( i ) < 1 / √k iO(nk)Δ(i)<1/k−−√ i O(nk)
Jaki będzie czas trwania tej procedury? Nie jestem pewien, ale oto kilka spostrzeżeń, które mogą pomóc. Każdy poziom rekurencji zmniejsza rozmiar problemu o około bitvectors (np. Od bitvectors do bitvectors). Dlatego rekurencja może wchodzić tylko na głębokości około . Jednak nie jestem od razu pewny, jak policzyć liczbę liści w drzewie rekurencyjnym (jest dużo mniej niż liści), więc nie jestem pewien, jaki czas powinien to prowadzić do.n / √kn/k−−√ n n - n / √n k √n−n/k−−√ k 3 √k−−√ k3k√
źródło
Szybsze rozwiązanie, gdy , przy użyciu mnożenia macierzyn≈kn≈k
Załóżmy, że . Naszym celem jest osiągnięcie lepszych wyników niż czas działania .n=kn=k O(n2k)=O(n3)O(n2k)=O(n3)
Możemy myśleć o wektorach bitowych i pozycjach bitowych jak o węzłach na wykresie. Pomiędzy węzłem bitvector a węzłem pozycji bitowej występuje krawędź, gdy bitvector ma 1 w tej pozycji. Powstały wykres jest dwustronny (z węzłami reprezentującymi bitvector z jednej strony i węzłami reprezentującymi położenie bitowe z drugiej) i ma węzłów.n+k=2nn+k=2n
Biorąc pod uwagę macierz przylegania wykresu, możemy stwierdzić, czy istnieje ścieżka dwóch przeskoków między dwoma wierzchołkami, poprzez podniesienie kwadratu i sprawdzenie, czy otrzymana macierz ma „krawędź” między tymi dwoma wierzchołkami (tj. Wejście krawędzi w macierz kwadratową jest niezerowa). Dla naszych celów zero wpisu w kwadratowej macierzy przylegania odpowiada nie nakładającej się parze wektorów bitowych (tzn. Rozwiązanie). Brak zer oznacza, że nie ma rozwiązania.MM MM
Kwadratowanie macierzy nxn można wykonać w czasie , gdzie wiadomo , że ma mniej niż a przypuszcza się, że wynosi .O(nω)O(nω) ωω 2.3732.373 22
Algorytm jest następujący:
Najdroższym krokiem jest podniesienie kwadratu macierzy sąsiedztwa. Jeśli to ogólny algorytm zajmuje czas , co jest lepsze niż naiwny czas .n=kn=k O((n+k)ω)=O(nω)O((n+k)ω)=O(nω) O(n3)O(n3)
To rozwiązanie jest również szybsze, gdy rośnie niezbyt dużo wolniej i nie zbyt szybko niż . O ile i , to jest lepsze niż . Dla co przekłada się na (asymptotycznie). Jeśli ogranicza się do 2, wówczas granice rozszerzają się w kierunku .kk nn k∈Ω(nω−2)k∈Ω(nω−2) k∈O(n2ω−1)k∈O(n2ω−1) (n+k)ω(n+k)ω n2kn2k w≈2.373w≈2.373 n0.731≤k≤n1.373n0.731≤k≤n1.373 ww nϵ≤k≤n2−ϵnϵ≤k≤n2−ϵ
źródło
Jest to równoważne ze znalezieniem wektora bitowego, który jest podzbiorem dopełniacza innego wektora; tzn. jego 1 występuje tylko wtedy, gdy 0 występuje w drugim.
Jeśli k (lub liczba 1) jest mała, możesz uzyskać czas , po prostu generując wszystkie podzbiory dopełniacza każdego bitvectora i umieszczając je w trie (używając cofania). Jeśli w trie zostanie znaleziony bitvector (możemy sprawdzić każdy przed wstawieniem podzbioru dopełniacza), mamy parę, która się nie nakłada.O ( n 2 k )O(n2k)
Jeśli liczba 1 lub 0 jest ograniczona do jeszcze niższej liczby niż k, wykładnik można zastąpić tym. Indeksowanie podzbiorów może dotyczyć każdego wektora lub jego dopełniacza, o ile w sondowaniu stosuje się coś przeciwnego.
Istnieje również schemat wyszukiwania supersetów w trie, który przechowuje każdy wektor tylko raz, ale przeskakuje bity podczas sond, dla których, moim zdaniem, jest podobna złożoność złożona; tzn. ma wstawienie ale wyszukiwania .o ( k ) o ( 2 k )o(k) o(2k)
źródło
Reprezentują wektory wiertła, z n x k macierzy M . Take I i J pomiędzy 1 i n .n×k M i j n
( M M T ) i j = ∑ l M i l M j l .
( M M T ) i j , iloczyn iloczynu i- tego i j- tego wektora, jest niezerowy, jeśli i tylko wtedy, gdy wektory i i j mają wspólną 1. Więc, aby znaleźć rozwiązanie, oblicz M M T i zwraca pozycję zerowego wpisu, jeśli taki wpis istnieje.(MMT)ij i j i j MMT
Złożoność
Korzystanie z naiwnego mnożenia wymaga operacji arytmetycznych O ( n 2 k ) . Jeśli n = k , wymaga operacji O ( n 2.37 ) przy użyciu całkowicie niepraktycznego algorytmu Coppersmith-Winograd lub O ( n 2.8 ) przy użyciu algorytmu Strassena. Jeśli k = O ( n 0,302 ) , problem można rozwiązać za pomocą operacji n 2 + o ( 1 ) .O(n2k) n=k O(n2.37) O(n2.8) k=O(n0.302) n2+o(1)
źródło