Przeskocz do treści

Delta mi!

Informatyczny kącik olimpijski

Nurkowanie

Adam Karczmarz

o artykule ...

  • Publikacja w Delcie: maj 2012
  • Publikacja elektroniczna: 28-04-2012
  • Autor: Adam Karczmarz
    Afiliacja: student, Wydział Matematyki, Informatyki i Mechaniki Uniwersytetu Warszawskiego
  • Wersja do druku [application/pdf]: (64 KB)

Tym razem zajmiemy się zadaniem Nurkowanie z Obozu Naukowo-Treningowego im. Antoniego Kreczmara w 2007 roku.

Załóżmy dla uproszczenia, że nurkowie są ponumerowani od math do math tak, że czasy, jakie potrzebują oni na przepłynięcie szczeliny, spełniają warunek math Sytuację daną w zadaniu opiszemy jako graf math  którego wierzchołki math odpowiadają nurkom. Nurkowie math i math są połączeni w math  krawędzią wtedy i tylko wtedy, gdy się lubią.

Zastanówmy się najpierw, kiedy problem nie ma rozwiązania. Każdy kolejny krok schematu jest równoważny wybraniu dwóch wierzchołków połączonych krawędzią w math  a następnie usunięciu z math  jednego z nich, odpowiadającego nurkowi, który został po drugiej stronie szczeliny i już nigdy stamtąd nie wróci. Jeśli więc math  na początku nie jest spójny, to na pewno przeprawa jest niewykonalna: po wykonaniu kursu liczba składowych nie maleje, więc gdy już nie będzie można wykonać żadnego kursu, pozostanie grupa co najmniej dwóch nurków, z których każdych dwóch się nie lubi.

Załóżmy więc, że math  jest spójny. Okazuje się, że wtedy rozwiązanie istnieje i każdy możliwy scenariusz przeprawy możemy skutecznie modelować za pomocą drzewa ukorzenionego math Ustanowimy nurka math który uczestniczy w ostatniej turze przeprawy, korzeniem naszego drzewa. Jeśli natomiast math i math płyną razem, po czym math wraca, to math zostanie synem math w math Jest jasne, że wykonywanie scenariusza przeprawy odpowiada ucinaniu liści naszego drzewa. Podobnie, mając dowolne ukorzenione drzewo rozpinające math  jesteśmy w stanie na jego podstawie skonstruować scenariusz przeprawy – wystarczy w dowolnej kolejności ucinać liście. Przypiszmy krawędziom drzewa math koszty czasowe odpowiadające kolejnym krokom. Jeśli math jest ojcem math w math to krawędź między nimi ma koszt math który, niestety, zależy nie tylko od wyboru nurków, ale także od skierowania krawędzi między nimi. Kosztem math niech będzie suma kosztów jego krawędzi pomniejszona o czas math potrzebny ostatniemu nurkowi na przeprawę ( math nie musi wracać podczas ostatniego kroku).

Okazuje się, że przy tak ustalonych wagach da się uprościć problem, aby móc zapomnieć o skierowaniu krawędzi i wyróżnionym korzeniu. Obliczmy koszt drzewa math ( math oznacza krawędź skierowaną od ojca math do syna math):

pict

Druga suma jest stała, więc koszt zależy tylko od pierwszego członu wyrażenia! Wystarczy więc znaleźć minimalne drzewo rozpinające grafu math  w którym krawędź math ma przypisany koszt math

Ponieważ na wejściu mamy dane explicite dopełnienie grafu math  możemy rozwiązać zadanie w czasie math  uruchamiając np. algorytm Prima. Aby rozwiązać zadanie szybciej, zastosujemy podejście podobne jak w algorytmie Borůvki. Przypomnijmy, że w algorytmie tym utrzymujemy las rozpinający math  i wykonujemy math  faz; w każdej fazie działania dodajemy do konstruowanego rozwiązania najtańszą krawędź wychodzącą z każdej dotychczasowej składowej lasu (rozstrzygając remisy w dowolny uporządkowany sposób).

Pokażemy, jak zrealizować jedną fazę algorytmu Borůvki. Oznaczmy przez math zbiór nurków, których nie lubi nurek math Niech math będzie zbiorem nurków dowolnej składowej dotychczasowego rozwiązania (na początku każdy nurek stanowi osobną składową). Niech math będzie szukaną najtańszą krawędzią wychodzącą z math  Jeśli math  to niech math  będzie nurkiem o najmniejszym numerze nienależącym do math ; krawędź math jest wtedy najtańszą krawędzią wychodzącą od nurka math i kandydatem na najtańszą krawędź z math  Wartość math możemy znaleźć w czasie math  przy założeniu, że zbiory reprezentujemy jako uporządkowane listy.

Pokażemy, jak to jeszcze usprawnić. Niech

display-math

Jeśli math i krawędź math jest najtańszą krawędzią wychodzącą z math  to math  w przeciwnym razie math dla pewnego math a krawędź math byłaby tańsza. Wobec tego zarówno sprawdzenie każdego sensownego kandydata math dla nurka math jak i obliczenie zbioru math wykonujemy w czasie math  Sumując koszty dla każdego wierzchołka składowej i dla każdej składowej, otrzymujemy sumaryczny koszt jednej fazy algorytmu:

display-math

Złożoność czasowa całego rozwiązania wynosi zatem math