Przeskocz do treści

Delta mi!

Loading

Informatyczny kącik olimpijski

Nim 3

Marcin Smulewicz

o artykule ...

  • Publikacja w Delcie: luty 2017
  • Publikacja elektroniczna: 31 stycznia 2017
  • Wersja do druku [application/pdf]: (33 KB)

W tym miesiącu omówimy zadanie Nim 3, które pojawiło się na Obozie Naukowo-Treningowym im. A. Kreczmara w 2013 roku.

Wielu Czytelników zapewne zna słynną grę "Nim": zaczynamy od pewnej liczby stosów kamyków, a następnie na przemian gracze wybierają niepusty stos i zabierają z niego dowolną dodatnią liczbę kamyków. Gracz, który nie może wykonać ruchu (bo skończyły się już kamyki), przegrywa. "Nim" jest silnie związany ze znanym twierdzeniem Sprague'a-Grundy'ego, jednak, niestety, nam się teraz nie przyda, gdyż dotyczy ona klasycznej wersji gry, a więc dla dwóch graczy. W naszym zadaniu natomiast w "Nima" będzie grało trzech braci - Antek, Bartek i Cezary. Począwszy od Antka po kolei będą oni wykonywać ruchy. Podobnie jak w "Nimie" gracz, który nie będzie mógł wykonać ruchu, przegra (zajmie trzecie miejsce). Gracz, który wykona ostatni ruch, zajmie pierwsze miejsce. Natomiast pozostały z trójki graczy zajmie drugie miejsce. Dla danych zestawów stosów mamy odpowiedzieć, kto wygra, jeśli każdy będzie grał optymalnie.

Podzielmy wszystkie możliwe stany gry na trzy zbiory: te stany, dla których wygra gracz rozpoczynający, oznaczmy jako A; te, dla których wygra gracz wykonujący drugi ruch - jako B, a te, dla których wygra gracz wykonujący ruch jako trzeci - jako C.

obrazek

W przypadku trzech graczy wcale nie musi być jasne, co to znaczy optymalna strategia. Następująca rekurencyjna definicja precyzuje to zgodnie z treścią zadania:

Stan końcowy (wszystkie stosy puste) należy do C. | Jeśli ze stanu w jednym ruchu da się otrzymać stan ze zbioru C, | to należy on do A | ; jeśli ze stanu w jednym ruchu da się otrzymać stan ze zbioru A | (a nie da się z C ), to należy on do B; | w przeciwnym razie należy on do |C.

Zachęcamy gorąco Czytelnika do nabrania przekonania, że taka definicja jest poprawna oraz że jest zgodna z intuicją.

Przejdźmy do samego rozwiązania. Nie owijajmy w bawełnę: zostało ono odgadnięte na podstawie zauważonych regularności w wynikach dla małych instancji problemu, które potem okazało się poprawne we wszystkich przypadkach. W ten sposób rozwiązuje się wiele trudnych zadań tego typu.

Wielkości stosów zapiszmy w systemie binarnym i policzmy osobno jedności, dwójki, czwórki, ósemki itd. Jeśli każda z tak obliczonych wartości jest podzielna przez 3, to stan należy do zbioru C. | Dla przykładu rozpatrzmy stosy zawierające odpowiednio 1, 1, 1, 5, 9, 12 oraz 13 kamyków, czyli w zapisie binarnym 1, 1, 1, 101, 1001, 1100 oraz 1101. Sześć z tych liczb jest nieparzystych, żadna z nich nie ma zapalonego (czyli równego 1) bitu na drugiej najmniej znaczącej cyfrze, trzy z nich mają jedną czwórkę i trzy z nich mają jedną ósemkę. Liczby 6, 0, 3, 3 są wszystkie podzielne przez 3, toteż rozpatrywany stan gry należy do zbioru C. | Zbiór |A określmy wprost z definicji jako te stany, z których w jednym ruchu da się otrzymać stan ze zbioru C. | Wszystkie pozostały stany tworzą |B.

Udowodnimy, że powyższe definicje spełniają warunki zadania.

Rozpatrzmy dowolny ruch, a dokładniej zapisy binarne liczby kamyków na wybranym stosie przed i po jego wykonaniu, oznaczmy je odpowiednio |X oraz |Y. Jeśli jakiś bit jest zapalony w , |X a nie jest zapalony w |Y, to liczba wystąpień tego bitu maleje o 1 w stanie gry. Liczba wystąpień danego bitu może też, oczywiście, zwiększyć się o 1, jak i pozostać bez zmian.

Ponieważ >Y, X więc najbardziej znaczący bit, na którym X oraz |Y się różnią, jest zapalony w X i zgaszony (równy 0) w Y (oznaczmy ten bit |K). W szczególności po wykonaniu ruchu ze stanu ze zbioru C | liczba wystąpień odpowiedniego dla ruchu bitu K | będzie przystawała do 2 przy dzieleniu przez 3. Natomiast liczby wystąpień bardziej znaczących bitów nadal będą podzielne przez 3.

Ponownie korzystając z tego samego argumentu, łatwo zauważyć, że otrzymany stan nie należy do A. Nie da się bowiem w jednym ruchu zwiększyć liczby wystąpień bitu K, nie zmieniając liczb wystąpień bardziej znaczących bitów. Reasumując: zgodnie z oczekiwaniami nie da się, ze stanu ze zbioru C w jednym ruchu otrzymać stanu z A |

Pozostaje sprawdzić warunek (dlaczego?): ze stanu nienależącego do C da się w co najwyżej dwóch ruchach otrzymać stan z C. Jeśli da się go otrzymać w jednym ruchu, to stan z definicji należy do A. | W przeciwnym razie, wykonując pierwszy z tych dwóch ruchów, otrzymujemy stan ze zbioru |A, czyli pierwotny stan należy do B. | Będziemy o takich dwóch ruchach myśleć jak o jednym specjalnym ruchu, który pozwala zabrać kamyki z dwóch stosów.

Weźmy dowolny stan spoza C. | Najbardziej znaczący bit, którego liczba wystąpień nie jest podzielna przez 3, oznaczmy K. | Jeśli liczba wystąpień |K przystaje do 2 przy dzieleniu przez 3, to wystarczy wykonać ruch na dwóch dowolnych stosach, które mają liczby kamieni z zapalonym bitem K. | Na obu gasimy bit K. | Mniej znaczące bity możemy naszym specjalnym ruchem ustawiać dowolnie (ruch będzie dozwolony, bo liczby kamieni na obu stosach zmaleją). W szczególności możemy je ustawić tak, aby był spełniony warunek należenia do zbioru C. | W przypadku, gdy liczba wystąpień bitu |K przystaje do 1 przy dzieleniu przez 3, sytuacja nie jest taka prosta. Wybieramy najpierw jeden stos z zapalonym bitem K, | oznaczmy go P |. Gasimy w nim bit K, a następnie mniej znaczące bity po kolei próbujemy tak ustawiać, aby liczba ich wystąpień w całym stanie gry dzieliła się przez 3. Jeśli udało nam się ustawić wszystkie, to rozpatrywany stan należy do A. | Możemy jednak napotkać przeszkodę, czyli bit dla którego zachodzi następujący warunek:

Jeśli ustawimy go na zero (jeden) w P |, to liczba jego wystąpień w stanie gry będzie dawać resztę 1 ( 2 ) przy dzieleniu przez 3.

Wówczas ustawiamy ten bit w P na zero, po czym jako drugi stos do naszego specjalnego ruchu wybieramy inny stos, który ma zapalony ów bit. Gasimy go, zapewniając zmniejszenie stosu oraz odpowiednią liczbę wystąpień bitu. Kolejne mniej znaczące bity możemy już teraz ustawiać dowolnie, otrzymując stan z |C.

Przekucie definicji zbiorów C | oraz A | w algorytm jest dość proste - działa on w czasie logM), 𝒪(N gdzie N oznacza liczbę stosów, a |M liczbę kamyków na największym stosie.

Na zakończenie zachęcamy Czytelnika do samodzielnego sprawdzenia, czy analogiczna strategia zadziała w przypadku większej liczby graczy.