Informatyczny kącik olimpijski
Nurkowanie
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 do tak, że czasy, jakie potrzebują oni na przepłynięcie szczeliny, spełniają warunek Sytuację daną w zadaniu opiszemy jako graf którego wierzchołki odpowiadają nurkom. Nurkowie i są połączeni w 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 a następnie usunięciu z 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 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 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 Ustanowimy nurka który uczestniczy w ostatniej turze przeprawy, korzeniem naszego drzewa. Jeśli natomiast i płyną razem, po czym wraca, to zostanie synem w Jest jasne, że wykonywanie scenariusza przeprawy odpowiada ucinaniu liści naszego drzewa. Podobnie, mając dowolne ukorzenione drzewo rozpinające jesteśmy w stanie na jego podstawie skonstruować scenariusz przeprawy – wystarczy w dowolnej kolejności ucinać liście. Przypiszmy krawędziom drzewa koszty czasowe odpowiadające kolejnym krokom. Jeśli jest ojcem w to krawędź między nimi ma koszt który, niestety, zależy nie tylko od wyboru nurków, ale także od skierowania krawędzi między nimi. Kosztem niech będzie suma kosztów jego krawędzi pomniejszona o czas potrzebny ostatniemu nurkowi na przeprawę ( 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 ( oznacza krawędź skierowaną od ojca do syna ):
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 w którym krawędź ma przypisany koszt
Ponieważ na wejściu mamy dane explicite dopełnienie grafu możemy rozwiązać zadanie w czasie 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 i wykonujemy 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 zbiór nurków, których nie lubi nurek Niech będzie zbiorem nurków dowolnej składowej dotychczasowego rozwiązania (na początku każdy nurek stanowi osobną składową). Niech będzie szukaną najtańszą krawędzią wychodzącą z Jeśli to niech będzie nurkiem o najmniejszym numerze nienależącym do ; krawędź jest wtedy najtańszą krawędzią wychodzącą od nurka i kandydatem na najtańszą krawędź z Wartość możemy znaleźć w czasie przy założeniu, że zbiory reprezentujemy jako uporządkowane listy.
Pokażemy, jak to jeszcze usprawnić. Niech
Jeśli i krawędź jest najtańszą krawędzią wychodzącą z to w przeciwnym razie dla pewnego a krawędź byłaby tańsza. Wobec tego zarówno sprawdzenie każdego sensownego kandydata dla nurka jak i obliczenie zbioru wykonujemy w czasie Sumując koszty dla każdego wierzchołka składowej i dla każdej składowej, otrzymujemy sumaryczny koszt jednej fazy algorytmu:
Złożoność czasowa całego rozwiązania wynosi zatem