Myśląc o jednym problemie, zdałem sobie sprawę, że muszę stworzyć wydajny algorytm rozwiązujący następujące zadanie:
Problem: otrzymujemy dwuwymiarowe kwadratowe pudełko o boku którego boki są równoległe do osi. Możemy spojrzeć na to z góry. Istnieją jednak również segmenty poziome. Każdy segment ma całkowitą współrzędną ( ) i współrzędne ( ) i łączy punkty i (spójrz na zdjęcie poniżej).
Chcielibyśmy wiedzieć, dla każdego segmentu jednostki na górze pudełka, jak głęboko możemy spojrzeć w środku w pionie, jeśli przejrzymy ten segment.
Przykład: biorąc pod uwagę i segmentów zlokalizowanych jak na poniższym obrazku, wynikiem jest . Zobacz, jak głębokie światło może dostać się do pudełka.m = 7 ( 5 , 5 , 5 , 3 , 8 , 3 , 7 , 8 , 7 )
Na szczęście dla nas zarówno , jak i m są dość małe i możemy wykonywać obliczenia offline.m
Najłatwiejszym algorytmem rozwiązującym ten problem jest brute-force: dla każdego segmentu przejdź przez całą tablicę i zaktualizuj ją w razie potrzeby. Daje nam jednak niezbyt imponujące .
Dużym ulepszeniem jest użycie drzewa segmentów, które jest w stanie zmaksymalizować wartości segmentu podczas zapytania i odczytać wartości końcowe. Nie będę tego dalej opisywał, ale widzimy, że złożoność czasu wynosi .
Wymyśliłem jednak szybszy algorytm:
Zarys:
Posortuj segmenty w malejącej kolejności współrzędnej (czas liniowy przy użyciu odmiany sortowania zliczającego). Teraz pamiętać, że jeśli szerokości jednostek, niskoprofilowy segment został objęty żadnym segmencie przed, nie po segment może związany wiązki światła przechodzącego przez ten szerokości jednostek, niskoprofilowy segmencie już. Następnie zrobimy przeciągnięcie linii od góry do dołu pudełka.x x
Teraz wprowadzimy kilka definicji: -jednostka segmentowa jest urojonym poziomym segmentem na przemiataniu, którego współrzędnymi są liczby całkowite i których długość wynosi 1. Każdy segment podczas procesu zamiatania może być albo nieoznaczony (to znaczy wiązka światła wychodząca z góra pudełka może dosięgnąć tego segmentu) lub oznaczona (odwrotna wielkość liter). Rozważ segment unit z , zawsze niezaznaczone. również zestawy . Każdy zestaw będzie zawierał całą sekwencję następujących po sobie segmentów jednostek (jeśli istnieją) z następującymi nieoznaczonymix x x 1 = n x 2 = n + 1 S 0 = { 0 } , S 1 = { 1 } , … , S n = { n } x człon.
Potrzebujemy struktury danych, która byłaby w stanie działać skutecznie na tych segmentach i zestawach. Użyjemy struktury find-union rozszerzonej o pole zawierające maksymalny indeks segmentu -jednostek (indeks segmentu nieoznaczonego ).
Teraz możemy efektywnie obsługiwać segmenty. Powiedzmy, że rozważamy teraz ty segment w kolejności (nazwij go „zapytaniem”), który zaczyna się od a kończy na . Musimy znaleźć wszystkie nieoznakowane segmenty unit, które są zawarte w segmencie (są to dokładnie te segmenty, na których wiązka światła kończy swoją drogę). Wykonamy następujące czynności: po pierwsze, znajdziemy pierwszy nieoznaczony segment w zapytaniu ( Znajdź reprezentanta zestawu, w którym znajduje się i uzyskaj maksymalny indeks tego zestawu, który z definicji jest segmentem nieoznaczonym ). Następnie ten indeksx 1 x 2 x i x 1 x y x x + 1 x ≥ x 2 znajduje się w zapytaniu, dodaj go do wyniku (wynikiem dla tego segmentu jest ) i zaznacz ten indeks ( zestawy Unii zawierające i ). Następnie powtarzaj tę procedurę, aż znajdziemy wszystkie nieoznakowane segmenty, czyli następne zapytanie Find daje nam indeks .
Zauważ, że każda operacja szukania unii zostanie wykonana tylko w dwóch przypadkach: albo zaczniemy rozważać segment (co może się zdarzyć razy), albo właśnie oznaczyliśmy segment jednostki (może się to zdarzyć razy). Zatem ogólna złożoność wynosi ( jest odwrotną funkcją Ackermanna ). Jeśli coś nie jest jasne, mogę rozwinąć więcej na ten temat. Może będę mógł dodać trochę zdjęć, jeśli będę miał trochę czasu.
Teraz dotarłem do „ściany”. Nie mogę wymyślić algorytmu liniowego, choć wydaje się, że powinien istnieć jeden. Mam więc dwa pytania:
- Czy istnieje algorytm czasu liniowego (to znaczy ) rozwiązujący problem widoczności segmentu poziomego?
- Jeśli nie, to jaki jest dowód na to, że problemem z widocznością jest ?
Odpowiedzi:
find ( ) może być zaimplementowany przy użyciu tablicy bitów z n bitami. Teraz za każdym razem, gdy usuwamy lub dodajemy element do L , możemy zaktualizować tę liczbę całkowitą, ustawiając odpowiednio wartość true lub false. Teraz masz dwie opcje w zależności od użytego języka programowania, a założenie, że n jest względnie małe, tj. Mniejsze niż l o n g l o n g i n t, czyli co najmniej 64 bity lub stała liczba tych liczb całkowitych:max n L n longlongint
Wiem, że to dość hack, ponieważ zakłada maksymalną wartość dla a zatem n może być postrzegane jako stała wtedy ...n n
źródło
long long int
jako co najmniej 64-bitową liczbę całkowitą. Jednak czy nie jest tak, że jeśli jest duże, a rozmiar słowa oznaczamy jako w (zwykle w = 64 ), to każde przyjmie O ( nfind
czas? Wtedy otrzymalibyśmy całkowiteO(mnNie mam algorytmu liniowego, ale ten wydaje się być O (m log m).
Sortuj segmenty na podstawie pierwszej współrzędnej i wysokości. Oznacza to, że (x1, l1) zawsze występuje przed (x2, l2) zawsze, gdy x1 <x2. Również (x1, l1) na wysokości y1 występuje przed (x1, l2) na wysokości y2 za każdym razem, gdy y1> y2.
Dla każdego podzestawu o tej samej pierwszej współrzędnej wykonujemy następujące czynności. Niech pierwszy segment będzie (x1, L). Dla wszystkich pozostałych segmentów podzbioru: Jeśli segment jest dłuższy niż pierwszy, zmień go z (x1, xt) na (L, xt) i dodaj go do podzestawu L w odpowiedniej kolejności. W przeciwnym razie upuść. Wreszcie, jeśli następny podzbiór ma pierwszą współrzędną mniejszą niż L, wówczas podziel (x1, L) na (x1, x2) i (x2, L). Dodaj (x2, L) do następnego podzbioru we właściwej kolejności. Możemy to zrobić, ponieważ pierwszy segment w podzbiorze jest wyższy i obejmuje zakres od (x1, L). Ten nowy segment może być tym, który obejmuje (L, x2), ale nie będziemy tego wiedzieć, dopóki nie spojrzymy na podzbiór, który ma pierwszą współrzędną L.
Po przejściu przez wszystkie podzbiory będziemy mieli zestaw segmentów, które się nie nakładają. Aby ustalić, jaka jest wartość Y dla danego X, musimy tylko przejść przez pozostałe segmenty.
Na czym więc polega złożoność: Sortowanie to O (m log m). Pętla przez podzbiory to O (m). Wyszukiwanie to także O (m).
Wydaje się więc, że ten algorytm jest niezależny od n.
źródło