Przeskocz do treści

Delta mi!

Informatyczny kącik olimpijski

Robot sortujący

Jakub Radoszewski

o artykule ...

  • Publikacja w Delcie: czerwiec 2012
  • Publikacja elektroniczna: 02-06-2012

Tym razem omówimy zadanie Robot sortujący (ang. Robotic Sort) z Mistrzostw Europy Środkowej w Programowaniu Zespołowym 2007 (CERC 2007).

W zadaniu występuje nietypowy algorytm sortowania math-elementowego ciągu liczb całkowitych. W  math-tym kroku (dla math) znajdujemy w ciągu math-ty najmniejszy element; załóżmy, że znajduje się on na pozycji math Następnie odwracamy fragment ciągu znajdujący się między pozycjami math-tą a  math-tą i w ten sposób rozważany element trafia na docelową pozycję w posortowanym ciągu. Naszym zadaniem jest efektywnie zasymulować ten algorytm, a dokładniej, wyznaczyć ciąg pozycji math Przykładowo, jeśli ciągiem do posortowania jest 3, 4, 5, 1, 6, 2, to wynikowy ciąg pozycji odpowiadających prawym końcom kolejnych odwróceń to 4, 6, 4, 5, 6, 6. Dla uproszczenia założymy, że wyjściowy ciąg jest permutacją liczb math W oryginalnym zadaniu ciąg nie musiał być różnowartościowy, ale sprowadzenie ogólnego przypadku do przypadku permutacji jest całkiem proste.

Bezpośrednia implementacja algorytmu sortowania przez odwracanie ma złożoność czasową math  Można się o tym przekonać, sprawdzając działanie algorytmu dla ciągu 2, 4, 6, 8, math – właśnie w tym przypadku wykonujemy największą liczbę operacji.

W takim razie spróbujemy zastosować jakieś inne podejście. Ponumerujmy elementy ciągu po kolei, od lewej do prawej, od 1 do math Załóżmy, że najmniejszy element ciągu znajduje się na pozycji math Wówczas po pierwszym odwróceniu elementy ciągu będą ustawione w następującej kolejności:

display-math

Widzimy, że tak naprawdę struktura ciągu zmieniła się dosyć nieznacznie. Jeśli teraz drugi najmniejszy element znajdował się, przykładowo, na pozycji math to po drugim odwróceniu ciąg będzie miał postać:

display-math

Domyślamy się już, co będzie dalej. Po math-tym odwróceniu ciąg będzie miał postać

display-math

dla pewnego math  przy czym math to numery math najmniejszych elementów ciągu, zaś math oznacza ciąg liczb math ustawionych w takim właśnie porządku (jeśli math) lub odwrotnie, malejąco (jeśli math).

Zauważmy, że używając takiej reprezentacji, kolejne odwrócenie w ciągu możemy wykonać w czasie math  o ile tylko będziemy dla każdego elementu math pamiętać, na której pozycji wyjściowego ciągu się znajdował (oznaczenie: math). Załóżmy, że math Znajdujemy teraz taką grupę math że math rozbijamy ją na dwie, a następnie między te dwie części wstawiamy, odwrócone, wszystkie wcześniejsze grupy. Przykładowo, jeśli math to wynikowy ciąg ma postać:

pict

Przypadek math rozpatrujemy analogicznie. Po każdej operacji przybywa co najwyżej jedna grupa – być może zero, jeśli math znajdowało się na skraju grupy math To jednak oznacza, że liczba grup może rosnąć liniowo, więc koszt czasowy całego algorytmu może być rzędu math  Pozostawiamy Czytelnikowi znalezienie złośliwego przykładu, wymuszającego wykonanie takiej liczby operacji – co ciekawe, poprzednio podany złośliwy przykład nie ma tej własności.

Mogłoby się wydawać, że ponieśliśmy porażkę – tyle wysiłku, a na końcu i tak algorytm jest kwadratowy. Możemy jednak osiągnąć lepszą złożoność czasową, jeśli tylko dostrzeżemy mocną stronę naszego algorytmu: otóż na samym początku jest on bardzo szybki. Koszt pierwszych math kroków algorytmu to math  Przyjmijmy math; wówczas podane kroki wykonujemy w czasie math  Kolejne kroki byłyby bardziej kosztowne, dlatego zamiast nich zrobimy... porządek. Możemy mianowicie wypisać explicite wszystkie wyrazy ciągu powstałego po math odwróceniach, ponumerować je kolejno, wyznaczyć od nowa tablicę indeksów poszczególnych elementów w ciągu math i kolejne odwrócenia wykonywać już za pomocą nowego ciągu.

Uporządkowanie ciągu po math odwróceniach zajmuje czas math  taki sam jak symulacja tych math odwróceń. W trakcie całego algorytmu takich większych faz musimy wykonać mniej więcej math co daje łączną złożoność czasową math

Na koniec warto dodać, że całe zadanie można rozwiązać także w czasie math  używając struktur danych opartych na drzewach zrównoważonych. Jednak takie rozwiązanie nie było nigdy autorowi kącika do szczęścia potrzebne.