Informatyczny kącik olimpijski
Kuglarz
W tym miesiącu omówimy zadanie Kuglarz z pierwszej rundy Potyczek Algorytmicznych 2014. Tytułowy kuglarz zaprasza przechodniów do następującej gry...
Zadanie 1. Na stoliku w rzędzie ustawił kubków z numerami a zawczasu pod niektórymi schował kauczukowe kulki. Jeśli grający dokładnie odgadnie, które to kubki, to dostaje nagrodę. Kuglarz odpłatnie udziela grającemu podpowiedzi. Za bajtogroszy (dla ) gotów jest zdradzić, jaka jest parzystość liczby kulek schowanych pod kubkami o kolejnych numerach Znając ceny wszystkich możliwych podpowiedzi, należy wyznaczyć koszt zebrania informacji, które pozwolą określić z całą pewnością, pod którymi kubkami znajdują się kulki. Ściślej rzecz biorąc, należy znaleźć najmniejszą taką liczbę że istnieje strategia zadawania pytań, która niezależnie od odpowiedzi kuglarza pozwala na zlokalizowanie kulek za co najwyżej bajtogroszy.
Spróbujmy wyznaczyć rozwiązanie dla tabelki kosztów z rysunku 1. Naiwne zadanie pytań o jednokubkowe przedziały kosztowałoby bajtogroszy. Czy da się lepiej? Oznaczmy przez podpowiedź na temat parzystości liczby kulek pod kubkami o numerach Zacznijmy od pytań o małych kosztach: pytanie daje nam informację, czy pod pierwszym kubkiem znajduje się kulka, a pytanie o parzystość liczby wszystkich kulek. Zadanie ich kosztuje bajtogrosze. Następne pytanie o małym koszcie to ale czy rzeczywiście opłaca się je zadawać? Nie, gdyż na podstawie poprzednich podpowiedzi, znamy parzystość kulek na pozycjach od 2 do 5.
Tę obserwację można nieco uogólnić: na podstawie odpowiedzi na dwa dowolne pytania z trójki oraz jesteśmy w stanie wyznaczyć odpowiedź na trzecie z tych pytań. Tutaj następuje kluczowy pomysł: zbudujmy graf pusty o wierzchołkach Dla każdego zadanego przez nas pytania będziemy w tym grafie łączyć krawędzią wierzchołki oraz Zachodzi teraz następujący fakt: jeśli wierzchołki oraz należą do tej samej spójnej składowej grafu, to albo zadaliśmy już kiedyś pytanie albo jesteśmy w stanie wyznaczyć na nie odpowiedź na podstawie dotychczasowych podpowiedzi kuglarza. Istotnie: jeśli wierzchołki te łączy ścieżka to przez indukcję można pokazać, że możemy wyznaczyć odpowiedzi na kolejne pytania
Z powyższych rozważań wynikają następujące wnioski. Nie opłaca się prosić o podpowiedzi, które spowodują powstanie cyklu w grafie, zatem po zadaniu dokładnie pytań graf który nam powstanie, będzie drzewem, a zdobyte informacje umożliwią zlokalizowanie wszystkich kulek (obecność kulki pod -tym kubkiem to odpowiedź na pytanie ). Zauważmy, że musimy zadać pytań, bo każda podpowiedź kuglarza daje nam co najwyżej 1 bit informacji, a musimy zgromadzić bitów, żeby wyznaczyć lokalizację kulek. Ponadto, kolejność zadawania pytań nie ma znaczenia. Pozostaje kwestia, jak wybierać pytania. Rozważając je w kolejności od najmniejszych kosztów i pomijając pytania, na które znamy odpowiedź, możemy znaleźć strategię dla przykładu o koszcie 7 bajtogroszy (Rys. 2).
Zauważmy, że postępując w taki sposób, obliczyliśmy nic innego, jak drzewo rozpinające o minimalnym koszcie dla nieskierowanego grafu pełnego, w którym każda para wierzchołków i jest połączona krawędzią o wadze Nasza strategia zachłanna działa dokładnie tak jak algorytm Kruskala, służący do wyznaczania tego drzewa. Ponieważ, jak powiedzieliśmy wyżej, każda strategia zadawania pytań wyznacza nam drzewo rozpinające, zatem, aby znaleźć optymalną strategię, należy znaleźć drzewo rozpinające o minimalnej wadze.
Standardowo robi się to, korzystając właśnie z algorytmu Kruskala lub algorytmu Prima z kolejką priorytetową zrealizowaną za pomocą kopca binarnego. Dla grafu o wierzchołkach i krawędziach oba algorytmy działają w czasie W naszym przypadku mamy jednak do czynienia z grafem pełnym, w którym co daje czas Można ten czas poprawić, zastępując kolejkę priorytetową w algorytmie Prima zwykłą tablicą, w której czas wyszukiwania będzie ale czas aktualizacji krawędzi będzie stały. Dzięki temu złożoność rozwiązania zmniejszy się do