Informatyczny kącik olimpijski
Dwa zadania z Potyczek
W tym kąciku omówimy dwa zadania z Potyczek Algorytmicznych 2012. Pomimo krótkich rozwiązań, zadania te wymagały od zawodników niemałej dozy pomysłowości.
Treść zadania Korniki wygodnie nam będzie streścić w terminologii numizmatycznej:
Zadanie 1 (Kornik). na stole w jednym rzędzie leży monet o nominałach Dwóch graczy na przemian wykonuje ruchy. Ruch polega na zabraniu monety z lewego końca, z prawego końca lub z obu końców rzędu naraz. Wiedząc, że każdy z graczy gra tak, by zmaksymalizować sumę wartości zabranych przez siebie monet, należy wyznaczyć wynik gry (różnicę między zyskiem pierwszego i drugiego gracza).
Symulując wprost reguły gry, dostajemy algorytm działający w czasie Wypełniamy kwadratową tablicę, gdzie oznacza wynik gry dla ciągu monet na pozycjach o numerach (zatem jest odpowiedzią do zadania). Jeśli pominiemy warunki brzegowe, rekurencja będzie następująca:
(*) |
Istnieje jednak efektywniejsze rozwiązanie. Załóżmy najpierw, że jest nieparzyste. Oznaczmy sumę nominałów monet na pozycjach nieparzystych oraz parzystych przez
Zauważmy, że pierwszy gracz ma strategię, która pozwala mu na zabranie wszystkich monet na pozycjach nieparzystych (niezależnie od ruchów drugiego gracza – w swoim pierwszym ruchu zabiera dwie monety, a w każdym kolejnym ruchu kopiuje ostatni ruch drugiego gracza). Gwarantuje mu to uzyskanie wyniku nie mniejszego niż Z kolei gracz drugi ma strategię, która pozwala mu na zabranie wszystkich monet na pozycjach parzystych (również kopiuje ruchy przeciwnika), co gwarantuje mu uzyskanie wyniku nie mniejszego niż Zatem obaj gracze uzyskają właśnie tyle, a wynikiem gry będzie
Dla parzystego nie widać, jak to zrobić równie prosto. Zatem pozostaje nam skorzystać ze wzoru Ograniczymy się jednak do wyznaczenia wartości dla Zauważmy, że przy obliczaniu każdej z nich pierwszy wyraz pod maksimum jest również tej postaci, natomiast dwa pozostałe dotyczą fragmentów długości nieparzystej, z którymi umiemy już sobie łatwo radzić. Rzeczywiście, jeśli stablicujemy sumy prefiksowe ciągu z naprzemiennym znakiem, możemy obliczyć wartość gry dla dowolnego takiego fragmentu w czasie stałym. Ostatecznie otrzymujemy rozwiązanie o złożoności czasowej
Zadanie 2 (Podatek). Dany jest graf nieskierowany reprezentujący sieć dróg pomiędzy miastami. Każda droga ma przypisaną stawkę podatku. Jadąc z miasta do miasta, musimy w każdym mieście pośrednim uiścić opłatę równą maksimum ze stawki podatku dla drogi, którą wjechaliśmy do miasta, i dla drogi, którą z miasta wyjedziemy. Dla miasta pierwszego i ostatniego rozważamy tylko jedną stawkę. Przykładowo, jadąc trasą jeśli przez oznaczymy stawkę podatku na drodze pomiędzy a zapłacimy
Należy podać minimalną opłatę przejazdu pomiędzy dwoma ustalonymi miastami.
Skorzystamy ze wzoru
Możemy wtedy zapisać dwukrotność opłaty, którą uiścimy w naszym przykładzie, jako
Pozostaje zauważyć istnienie bijekcji pomiędzy ścieżkami z do w grafie a ścieżkami z do w grafie w której dwukrotność opłaty za ścieżkę w jest równa zwykłej wadze ścieżki w Graf ma wierzchołków i krawędzi, więc uruchomienie na nim algorytmu Dijkstry zajmie czas