Sunteți pe pagina 1din 27

Lectia 5. Strategii de joc.

Jocul NIM

Strategii de joc. Jocul NIM

Introducere
Domeniu relativ nou şi încă necercetat în adâncime, teoria jocurilor este o
ramură a matematicii în care de multe ori primează inventivitatea şi nu
cunoştinţele. Tocmai din acest motiv, în cadrul acestui articol vom introduce
câteva noţiuni teoretice care ne vor ajuta în rezolvarea unor probleme din teoria
jocurilor. Ingeniozitatea celor pasionaţi poate fi testată prin introducerea unor
probleme de teoria jocurilor la concursurile de matematică şi informatică.
Deoarece în România teoria jocurilor nu este studiată în şcoli, problemele din
acest domeniu pot pune în dificultate concurenţii.

Jocuri combinatoriale
Definiţia 1 Prin joc se înţelege un şir de decizii (acţiuni, mutări), luate de părţi
ale căror interese sunt contrare.
Jocurile pot fi clasificate după numărul de jucători, după natura mutărilor
(libere sau aleatoare, cum ar fi zaruri, cărţi de joc, etc), după cantitatea de
informaţie disponibilă (cunoaştem sau nu informaţii despre toate mutările
precedente?).
Jocurile despre care discutăm în continuare sunt jocuri pentru 2 jucători,
care mută alternativ, mutările sunt libere (nu există nimic aleator) şi informaţia
este completă (cunoaştem toate mutările efectuate).

Definiţia 2 Spunem că un jucător are strategie sigură de câştig dacă acesta va


câştiga, indiferent de modul în care ar încerca adversarul să îi împiedice
victoria.

Exemple de strategii de joc

2.1 Strategia simetriei


Un jucător imită mutările celuilalt jucător, efectuând o mutare simetrică
cu a adversarului (simetria se stabilește în funcție de o axă de simetrie sau de o
axă de simetrie)
Exemplul 1
O bandă de hârtie este împărțită în n căsuțe. Alternativ, doi jucători X şi Y
hașurează câte k căsuțe adiacente, nehașurate. Cel care nu mai poate muta
pierde. Iniţial mută X. Se ştie că n şi k au aceeaşi paritate. Se cere:
a) Să se determine dacă jucătorul X are strategie sigură de câştig.
b) În caz afirmativ se cere să se programeze mutările lui X, cele ale lui Y fiind
citite de la intrare.

Soluţie
Lectia 5. Strategii de joc. Jocul NIM

Initial X va haşura căsuţele din centrul benzii, împărţind în acest fel banda de
hârtie în două benzi de dimensiuni egale, putând în acest fel să imite simetric
mutările lui Y.

Exemplul 2
Fie o tablă dreptunghiulară împărţită în n*m căsuţe. Alternativ, doi jucători X şi
Y haşurează câte două căsuţe adiacente, nehaşurate până în acel moment. Cel
care nu mai poate muta pierde. Iniţial mută jucătorul Y. Cel puţin unul dintre
numerele m, n este un număr par. Se cere:
a) Să se determine dacă jucătorul X are strategie sigură de câştig.
b) În caz afirmativ se cere să se programeze mutările lui X, cele ale lui Y fiind
citite de la tastatură.
Soluţie
Vom căuta o axă de simetrie (pentru că cel puţin unul dintre m şi n este par). Să
alegem ca axa de simetrie linia care este paralelă cu marginea tablei care are un
număr impar de pătrăţele (dacă aceasta există) şi este egal distanţată de cele
două margini. Dacă Y joacă de o parte a axei de simetrie, X va juca în cealaltă
parte, dar dacă Y va haşura două pătrăţele, unul de o parte a axei, iar celălalt de
cealaltă parte, atunci X nu mai are cum să îl imite simetric, de aceea este
evidentă necesitatea unei noi axe de simetrie, lucru care este posibil, doar daca
ambele numere n, m sunt pare. Dacă doar unul din numerele n, m este par, atunci
Y, va putea hasura primele doua patratele pe linia (coloana) din centru, avand o
patratica de o parte a axei, iar cealalta patratica de cealalta parte a axei, iar apoi
va imita simetric mutarile lui X.
In concluzie, X are strategie sigura de castig, daca ambele numere n, m sunt
pare, iar o poziţie (p,q), va avea simetrica de coordonate (n+1-p,m+1-q).

2.2 Strategia perechilor


Ideea strategiei constă în gruparea mutărilor pe perechi de mutări. La fiecare
pas, unul dintre jucători va putea efectua mutarea pereche a mutării efectuate de
adversar.
Ca şi în strategia simetriei, este posibil ca prima mutare să nu poată fi
împerecheată, cu o altă mutare, dar apoi (după ce această mutare este efectuată)
să fie posibilă realizarea acestui lucru.

Exemplul 1
Se dă o foaie de hârtie dreptunghiulara, împărţită în n*m căsuţe. Alternativ, doi
jucători X şi Y decupează una dintre căsuţele care este învecinată pe orizontală,
sau verticală cu ultima căsuţă decupată. Cel care nu mai poate muta pierde.
Iniţial mută X şi va decupa o căsuţă oarecare. O căsuţă poate fi decupată o
singură dată, deci nu este permisă parcurgerea de două ori a aceleiaşi căsuţe. Se
cere:
a) Să se determine daca X are strategie sigură de câştig.
Lectia 5. Strategii de joc. Jocul NIM

b) În caz afirmativ să se programeze mutarile lui X, cele ale lui Y fiind citite de la
intrare
Solutie
Ideea de bază este gruparea mutărilor în perechi. În acest caz încercăm să
acoperim tabla cu piese de domino. Dacă tabla are un număr impar de căsuţe,
atunci nu este posibilă o acoperire completa a acesteia, dar in schimb o putem
acoperi, daca eliminam, spre exemplu coltul din stanga sus, deoarece pe linia 1,
vom ramane cu un numar par de casute, pe care le putem acoperi complet, fără
să suprapunem piese, iar în rest mai ramane o suprafaţă dreptunghiulara care are
un numar par de casute, care pot fi acoperite cu dominouri.
Daca tabla are un numar par de casute, atunci cel de-al doilea jucator (Y) are
strategie sigura de câştig, deoarece la fiecare pas, va juca în acea căsuţa, care se
afla sub acelaşi domino cu casuta decupata de X. Daca tabla are un numar impar
de casute, atunci jucatorul care muta primul (X) are strategie sigură de câştig,
iniţial el decupand casuta care nu a fost acoperita de nici un Domino, apoi la
fiecare pas decupand casuta pereche casutei decupate de Y.

Exemplul 2
Se da o foaie de hârtie dreptunghiulară, împărţită în n*n căsuţe. Alternativ, doi
jucatori X şi Y decupeaza una din casutele care este L-invecinata cu ultima
casuta decupata. Două casute se numesc L-învecinate, dacă există o săritură a
calului care să treacă de la una la alta (dintr-o singură mutare). Cel care nu mai
poate muta pierde. O casuta poate fi decupata o singura data, deci nu este
permisa parcurgerea de doua ori a aceleiaşi căsuţe. Se cere:
a) Sa se determine daca X are strategie sigura de castig.
b) In caz afirmativ sa se programeze mutarile lui X, cele ale lui Y fiind citite de
la intrare.
Soluție
O mutare este identica cu o saritura a calului, intr-o pozitie noua,
neparcursa. Trebuie sa gasim o impartire a casutelor tablei in perechi, astfel
incat fiecare casuta sa faca parte dintr-o singura pereche. Sa definim o pereche
de casute, ca fiind doua casute astfel incat un cal poate sa sara direct de pe una
pe alta. Deci daca reusim sa gasim un drum al calului, care sa treaca o singura
data prin fiecare casuta, atunci problema este rezolvata, deoarece casuta cu
numar de ordine impar in cadrul drumului, va fi prima casuta a Domino-ului in
forma de L, definit anterior, iar casutele cu numar de ordine par vor fi cea de-a
doua casuta a Domino-ului.
Pentru n par, jucatorul Y are strategie sigura de castig, la fiecare pas el
jucand in casuta pereche celei in care a jucat X.
Pentru n impar, jucatorul X are strategie sigura de castig, initial el
decupand pozitia din centru, apoi la fiecare pas va juca mutarea pereche a
mutarii executate de Y.
Determinarea unui drum al calului care sa treaca o singura data prin
fiecare casuta, se face poate prin urmatorul procedeu:
- Se pleaca din pozitia (1,1). Se poate pleca la fel de bine din orice alta pozitie.
Lectia 5. Strategii de joc. Jocul NIM

- La fiecare pas se sare in acea casuta din care sunt cele mai putine posibilitati
de a sari, mai putin in casuta din centru.

2.3 Strategia parităţii


Denumirea acestei strategii vine de la existenţa a două tipuri de
configuraţii (pară, respectiv impară) în care se poate afla la un moment dat jocul
(partida). Ele sunt definite, în avantajul unuia dintre jucători (să-l numim pe
acesta X, iar pe celălalt Y), astfel la fiecare pas, jucatorul X, va putea face o
mutare convenabilă care sa transforme o configuraţie de joc impară într-o
configuraţie de joc pară. Spre deosebire de X, jucătorul Y, va putea să treacă la
fiecare mutare, doar dintr-o configuraţie pară într-una impară. Starea finală a
jocului este o configuraţie pară.
Mai exact, jocul îndeplineşte (printre altele) următoarele condiţii:
1. Se joacă între doi parteneri, care muta alternativ. Cel care nu mai poate muta
pierde.
2. Putem defini o partiţie cu două clase (A si B) a mulţimii configuraţiilor
jocului, astfel încât:
a) Configuraţia finală să aparţină mulţimii A.
b) Orice mutare aplicată unei configuraţii din A, va transforma această
configuraţie într-o configuraţie din B. Pentru configuraţia finală nu există
nici o mutare care să o transforme într-o altă configuraţie.
c) Există o mutare convenabilă, care realizeaza transformarea unei
configuraţii din B într-o configuraţie din A.
În aceste condiţii va câştiga (dacă joacă fără greşeli) acel jucător care la
momentul în care este la mutare va găsi jocul într-o configuraţie impară.
Pentru a câştiga el trebuie să treacă într-o configuraţie pară, lucru posibil,
datorită modului cum am definit aceste poziţii.

Exemplul 1
Se dă o stivă cu n monede. Alternativ, doi jucători X şi Y pot extrage din
stivă maximum k monede. Cel care nu mai poate muta, pierde. Iniţial
mută X. Se cere:
a) Să se determine dacă X are strategie sigură de câştig.
b) În caz afirmativ să se programeze mutările lui X, cele ale lui Y fiind
citite de la intrare. (Jocul Bachet, 1612)
Soluţie
Strategia câştigătoare se bazează pe împărţirea configuraţiilor de joc în două
mulţimi disjuncte, şi anume:
- configuraţia pară se defineşte ca fiind acel n, cu proprietatea ca n%(k+1)==0
- configuraţia impară se defineşte ca fiind acel n, cu proprietatea ca n%(k+1)!=0

Teorema 1
Lectia 5. Strategii de joc. Jocul NIM

În urma oricărei mutări, aplicate unei configuraţii pare, se trece într-o


configuraţie impară.

Demonstraţie
Configuraţia pară este caracterizată de faptul ca n este divizibil cu k+1. La
fiecare pas putem extrage p monede, p cuprins intre 1 si k. Deci în noua
configuraţie n nu va fi divizibil cu k+1.

Teorema 2
Dintr-o configuraţie impară, se poate trece, în urma unei mutări convenabile,
într-o configuraţie pară.

Demonstraţie
Să presupunem că în stivă avem n monede. Cea mai apropiată configurație pară
(cu mai puţine monede decât n) se obţine extrăgând n%(k+1) monede.
Deci jucătorul X fiind primul la mutare, va câştiga (mutând corect, fără
greşeli) dacă n%(k+1)!=0.

Exemplul 2
Se dă o stivă cu n monede. Dacă numărul monedelor din stivă, este mai
mare decât un număr natural dat p, atunci din stivă se pot extrage maximum k1
monede, în caz contrar se pot extrage maximum k2 monede. Alternativ, doi
jucători X şi Y, extrag din stivă monede, respectând condiţia de mai sus. Inițial
mută X. Se cere:
a) Să se determine dacă X are strategie sigură de câştig.
b) În caz afirmativ să se programeze mutările lui X, cele ale lui Y fiind citite de
la intrare.
Soluţie
Să determinam cel mai mare număr natural w, mai mic sau egal cu p, astfel
încât w%(k2+1)==0. Deci cel care va ajunge să ia primul din stiva cu w
monede, va pierde. Deci pentru ca Y să fie obligat să extragă dintr-o stivă cu w
monede, X va trebui să mute în aşa fel încât să lase în stivă w monede. Asta
înseamnă că X trebuie să câştige pentru o stivă de n-w monede, din care se pot
extrage la fiecare pas, maxim k1 monede, lucru realizabil doar dacă n-w este
multiplu de k1+1.

Exemplul 3.
Jocul NIM
Se dau n grămezi, fiecare conţinând un anumit număr de pietre. Doi jucători vor
începe să ia alternativ din pietre, astfel: la fiecare pas, jucătorul aflat la mutare
trebuie să îndepărteze un număr nenul de pietre dintr-o singură grămadă.
Câştigătorul este cel care ia ultima piatră.
Cerinţă
Lectia 5. Strategii de joc. Jocul NIM

Pentru t configuraţii de joc date, să se determine dacă jucătorul care ia primele


pietre are strategie sigură de câştig.
Date de intrare
Pe prima linie a fişierului de intrare nim.in se va afla numărul t de
configuraţii. Pe următoarele 2*t linii se vor afla descrierile jocurilor, astfel: pe
linia 2*i se va afla numărul ni de grămezi care alcătuiesc jocul i, iar pe linia
2*i+1 se vor afla ni numere, dimensiunile grămezilor.
Date de ieşire
În fişierul de ieşire nim.out se vor afişa t linii, pe linia i aflându-se mesajul
"DA", dacă primul jucător are strategie sigură de câştig în jocul i, respectiv
"NU", în caz contrar.
Restricţii
 1 ≤ t ≤ 100

 1 ≤ ni ≤ 10 000
 Numărul de pietre din oricare grămadă este natural pozitiv mai mic sau egal
cu 2*109
Exemplu
nim.in nim.out
2 NU
4 DA
1 3 5 7
3
4 8 17

Soluţie
Pentru cazul trivial în care numãrul de grãmezi este egal cu 1, primul jucator are
evident strategie de câştig, el putând lua toate pietrele din grãmadã.
Dacã numãrul de grãmezi este egal cu 2, primul jucãtor are strategie de câştig
atunci când numãrul de pietre din prima grãmadã este diferit de numãrul de
pietre din cea de-a doua, strategia lui fiind cea de a aduce tot timpul grãmada
mai mare la numãrul de pietre al grãmezii mai mici, şi cum jocul este finit,
înseamnã cã primul jucãtor o sã aducã jocul în starea (0, 0).
Dacã numãrul de grãmezi este mai mare decât doi strategia se complicã şi nu se
mai observã cu "ochiul liber". Dar ideea este similară.
O strategie posibilă ar fi următoarea:
Considerăm reprezentările binare ale numărului de pietre din fiecare grămadă.
Efectuăm operaţia XOR (sau exclusiv ^) pe aceste reprezentări.
Dacă rezultatul acestei operaţii este diferit de 0, primul jucător va avea
strategie sigură de câştig.
Dacă rezultatul acestei operaţii este 0, al II-lea jucător va avea strategie
sigură de câştig (deci primul jucător este într-o stare de pierdere).
Să demonstrăm că primul jucător are strategie sigură de câştig dacă
rez=p1^p2^…pn≠0.
Ideea este de a muta astfel încât să aducă pe al doilea jucător într-o stare de
pierdere, adică pentru care rez=p1^p2^…pn=0.
Lectia 5. Strategii de joc. Jocul NIM

Fie i cel mai semnificativ bit egal cu 1 din rez. Alegem o grămadă j care
are în reprezentarea sa binară acest bit egal cu 1.
Voi extrage din această grămadă pj-(pj^rez) pietre (pj^rez este mai
mic decât pj, pentru că bitul i se anulează) După această mutare p1^p2^…
pn=0, iar al doilea jucător va trebui să extragă un număr de pietre, ceea ce va
conduce iarăşi la o stare pentru care p1^p2^…pn≠0 (adică primul jucător va
avea ce muta).
Dacă suntem într-o stare cu rez=0, orice mutare ar face jucătorul care este la
rând va aduce jocul într-o stare cu rez≠0 (să spunem că din gămada j va luam
x piese; bitul cel mai semnificativ din x se schimbă sigur)
De exemplu, dacã avem o gramadã cu o piatrã, o gramadã cu trei pietre, o
gramadã cu cinci pietre şi o gramadã cu şapte pietre:
o
ooo
ooooo
oooooo
Atunci vom avea:
1 = (0001)
3 = (0011)
5 = (0101)
7 = (0111)
rez=(0000)
Conform propoziţiei de mai sus aceastã stare este de pierdere.
Să considerăm un alt exemplu
N=3 p=(4,8,17)
Reprezentările binare sunt
p1: 00100
p2: 01000
p3: 10001
rez:11101
Cel mai semnificativ bit 1 din rez corespunde lui 24
Aleg o grămada j pentru care pj are bitul corespunzător lui 24 egal cu 1 (aceasta
trebuie să existe şi este p3)
Extrag din grămada 3: p3-(rez^p3) piese, adică în grămada p3 rămân p3^rez
piese
rez: 11101
p3: 10001
rez^p3: 01100=12 piese
Extrag p3-(rez^p3)=17-12=5 piese din grămada 3 şi se obţine p3=12:
p1: 00100
p2: 01000
p3: 01100
rez:00000
Orice mutare ar face al doilea jucător, ca determina ca rez să devină iarăşi ≠0.
Lectia 5. Strategii de joc. Jocul NIM

#include <bits/stdc++.h>
using namespace std;
ifstream fin("nim.in");
ofstream fout("nim.out");
int main()
{
int T,x;;
fin>>T;
for (int t = 0; t < T; t++)
{
int n;
fin>>n;
int val = 0;
for (int i = 1; i <= n; i++)
{
fin>>x;
val ^= x;
}
if (val != 0)fout<<"DA\n";
else fout<<"NU\n";
}
return 0;
}

Probleme similare
Problema 1
Pe o tablã de şah, care are n • m cãsuţe, sunt plasaţi pe prima linie n pioni albi şi
pe ultima linie n pioni negri. Fiecare dintre cei doi jucãtori poate muta un singur
pion, care îi aparţine, un numãr strict pozitiv de cãsuţe în sus sau în jos, astfel
încât sã nu ajungã vreun pion alb sã fie mai jos decât pionul negru de pe aceeaşi
coloanã. Pierde jucãtorul care nu mai poate muta.
Soluţie
Aceastã problemã este o deghizare a jocului NIM, numãrul de pãtrãţele libere
între pionul alb şi pionul negru de pe coloana i putând fi considerat numãrul de
pietre din grãmada i. Singura diferenţã este cã se pot adãuga pietre la grãmadã
(existând posibilitatea mutãrii înapoi).
Aceastã problemã se rezolvã uşor, jucãtorul care are strategie de câştig putând
evita asemenea mutãri. O astfel de mutare poate fi utilã numai pentru jucãtorul
care este într-o poziţie de pierdere.
Când jucatorul care nu are strategie de câştig mutã înapoi x casuţe, celãlalt
jucãtor va muta pionul propriu de pe aceeaşi coloanã cu x cãsuţe în faţã, astfel
ajungându-se la aceeaşi stare cu cea existentã cu douã mutãri anterior
(considerând diferenţa poziţiilor).
Problema 2
Această problemã a fost propusã spre rezolvare participanţilor la barajul pentru
selecţia lotului naţional din 1997.
Pe o linie sunt plasate la coordonate întregi 2 • n piese roşii şi albastre.
Fiecare piesã roşie poate fi mutatã în dreapta oricâte poziţii astfel încât sã nu
sarã peste o piesã albastrã, iar piesele albastre pot fi mutate oricâte poziţii la
Lectia 5. Strategii de joc. Jocul NIM

stânga astfel încât sã nu depăşeascã vreo piesă roşie. Piesele vor alterna: roşu,
albastru, roşu, albastru etc. Pierde jucãtorul care nu mai poate muta.
Soluţie
Aceastã problemã poate fi, de asemenea, redusã la jocul NIM. Diferenţele
poziţiilor perechilor de piese roşii şi albastre consecutive constituie numãrul de
pietre al grãmezilor din jocul NIM.

Problema 3 (Misere NIM)


Se considerã n grãmezi de pietre, jucãtorii mutã alternativ, fiecare jucãtor
extrãgând oricâte pietre dintr-o singurã grãmadã. Cel care ia ultima piatră pierde
jocul.
Strategia acestui joc este similarã cu cea aplicatã în jocul NIM cu câteva mici
diferenţe. Jucãtorul care are strategie de câştig în poziţia curentã în cadrul
jocului NIM face aceeaşi mutare pe care ar face-o în cazul jocului NIM,
exceptând cazul în care aceastã mutare lasã doar grãmezi cu o singurã piatrã şi
numãrul acestor grãmezi este par.
În aceastã situaţie, dacã ar trebui sã ia x pietre, jucãtorul poate lua x - 1 pietre
din grãmada actualã, pentru ca numãrul de grãmezi sã fie impar şi adversarul sã
facã ultima mutare.

Jocul TZIANSITZI (Concursul de Informatică prin E-mail, Oradea, 1997)


Jocul TZIANSITZI, ceea ce în traducere înseamnă "alegerea pietrelor", este un
joc popular din China. Doi jucători extrag alternativ pietre din două grămezi. La
fiecare mişcare un jucător poate extrage acelaşi numar de pietre din ambele
grămezi sau un numar oarecare de pietre din una dintre grămezi. Câştigă
jucătorul care ia şi ultima piatră.
Cerinţa
Se cere sa testati daca, pentru o configuratie data, primul jucator are sau nu
strategie de castig si daca da sa programati mutarile primului jucator, mutarile
celui de al doilea jucator fiind citite de la tastatura.
Date de intrare
Programul nu citeste date din nici un fisier.
Date de iesire
Programul nu va scrie date in nici un fisier.
Interactiune
Programul vostru va interactiona cu un program al comisiei care ruleaza în
paralel. În cadrul unui set de test (test-case), programul vostru va trebui sa dea
raspunsul corect pentru mai multe teste. Pentru fiecare test din set, interactiunea
are urmatorul format:
1. Programul vostru citeste o linie de la intrarea standard, care contine doua
numere naturale n m separate printr-un spatiu (n este numarul de pietre din
prima gramada, m este numarul de pietre din a doua gramada pentru testul
respectiv). Daca n si m sunt nule, inseamna ca setul de test s-a terminat.
Lectia 5. Strategii de joc. Jocul NIM

2. Apoi, programul vostru va determina daca primul jucator are sau nu strategie
sigura de castig. In caz afirmativ, va scrie o linie ce contine doar valoarea 1. In
caz contrar (deci daca primul jucator nu are strategie sigura de castig) se va
scrie o linie ce contine doar valoarea 0 (zero) si apoi o linie linie care contine
cuvantul DONE.
3. Daca primul jucator are strategie sigura de castig, programul vostru va
efectua un numar de runde. O runda consta din scrierea unei linii la iesirea
standard, care descrie operatia efectuata de primul jucator în runda respectiva. O
operatie este descrisa prin numarul gramezii din care jucatorul extrage pietre (1
pentru prima gramada, 2 pentru cea de a doua, respectiv 3 pentru ambele
gramezi), urmat de un spatiu, apoi de un numar natural nenul care reprezinta
numarul de pietre extrase. Apoi, se va citi o linie de intrarea standard care
descrie operatia efectuata de al doilea jucator (operatia fiind specificata in
acelasi mod). Când programul vostru a executat ultima mutare, afiseaza o linie
speciala, continand numai cuvantul DONE
Punctaj
Programul vostru va primi punctajul corespunzator setului de teste curent daca
si numai daca a rezolvat corect toate testele continute in setul respectiv.
Programul vostru primeste 0 puncte pe un anumit test in urmatoarele situatii : -
afiseaza in cadrul unei runde o operatie ce nu poate fi executata la momentul
respectiv; - afiseaza ca primul jucator are strategie sigura de castig atunci cand
nu are (sau invers); - atunci cand primul jucator are strategie sigura de castig,
programul vostru nu castiga; - formatul de afisare impus in problema nu este
respectat.
Instructiuni de programare
Programatorii în C/C++ trebuie sa execute flush dupa ce au terminat de scris o
linie completa la iesire. Acest lucru este valabil si pentru linia continând DONE
În cazul programelor scrise în C++ si utilizarea iostreams, se va folosi
urmatoarea secventa pentru citirea de la intrarea standard si scrierea la iesirea
standard: cin>>x; cout<<op<<'\n'<<flush;
În cazul programelor în C sau C++ si utilizarea scanf si printf, se va folosi
urmatoarea secventa pentru citirea de la intrarea standard si scrierea la iesirea
standard: scanf ("%d", &x); printf("%d\n",op); fflush (stdout);
În cazul programelor în Pascal se va folosi urmatoarea secventa pentru citire de
la intrarea standard se utilizeaza readln, iar pentru afisarea unei linii se
utilizeaza writeln : readln(x); writeln(op);
Restrictii si precizari
1 <= n <= 1016 Intr-un set de teste sunt cel mult 7 teste.
Exemplu de interactiune
Operatie Semnificatie
Citeste 1 2 n=1, m=2 Primul jucator nu are strategie
Scrie 0 sigura de castig S-a terminat primul test
Scrie DONE n=5, m=6
Citeste 5 6
Scrie 1 Primul jucator are strategie sigura de castig
Lectia 5. Strategii de joc. Jocul NIM

Scrie 2 3 Primul jucator extrage 3 pietre din


Citeste 1 1 gramada 2 Al doilea jucator extrage 1
Scrie 3 2 pietre din gramada 1 Primul jucator
Citeste 3 1 extrage 2 pietre din ambele gramezi Al
Scrie 1 1 doilea jucator extrage 1 pietre din ambele
Scrie DONE gramezi Primul jucator extrage 1 pietre din
Citeste 0 0 gramada 1 Acest test s-a terminat Acest
test-case s-a terminat

Soluţie
Rezolvarea se bazează pe reprezentarea numerelor naturale în sistemul de
numeraţie Fibonacci.
Definiţie
Perechea (n, m), cu n<m se numeşte distinsă dacă:
1. reprezentarea Fibonacci a lui n se termină cu un număr par de zerouri;
2. reprezentarea Fibonacci a lui m se obţine din reprezentarea Fibonacci a lui n
prin adăugarea la sfârşit a unui 0.
Exemple:
1. n = 1 (1, în sistemul Fibonacci) , m = 2 (10, în sistemul Fibonacci)
2. n = 3 (100, în sistemul Fibonacci), m = 5 (1000, în sistemul Fibonacci)
3. n = 4 (101, în sistemul Fibonacci), m = 7 (1010, în sistemul Fibonacci)
Propoziţie
Orice număr natural aparţine unei singure perechi distinse.
Demonstraţie
Dacă reprezentarea numărului în sistemul de numeraţie Fibonacci se termină cu
un număr par de zerouri, al doilea număr din pereche se obţine adăugând un 0
final, altfel al doilea număr din pereche se obţine prin suprimarea unui 0 final.
Propoziţie
În şirul {m - n | (n, m) pereche distinsă} fiecare număr natural apare o singură
dată.
Demonstraţie
Fie d ∈ N, iar xpxp - 1...x1, reprezentarea Fibonacci a lui d.
d = xpxp - 1...x1 = xp∙ fp + xp - 1∙ fp-1+...+x1f1
Dacă reprezentarea Fibonacci a lui d se termină cu un număr impar de zerouri,
atunci
n = xpxp - 1...x10 = xp∙ fp + 1 + xp - 1∙ fp+...+x1∙ f2 (5)
m = xpxp - 1...x100 = xp∙ fp + 2 + xp - 1∙ fp + 1+...+x1∙ f3. (6)
m - n = xp∙ (fp+2 - fp +1)+ xp - 1∙ (fp + 1-fp)+...+x1∙ (f3 - f2)= xp∙ fp + xp - 1∙ fp-1+...+x1f1 = d
Dacă reprezentarea Fibonacci a lui d se termină cu un număr par de zerouri,
deci x1 = x2 = x2k = 0, x2k+1 ≠ 0, atunci:
n = xpxp - 1...x2k+2 0101...01(de k+1 ori )= xp∙ fp+1 + xp - 1∙ fp+...+x2k+2 ∙ f2k+3 + (f2k +
1 + f2k - 1+...+ f3 + f1)
Lectia 5. Strategii de joc. Jocul NIM

m = xpxp - 1...x2k+2 0101...010(de k+1 ori) = xp∙ fp+2 + xp - 1∙ fp+1+...+x2k+2 ∙ f2k+4 +


(f2k+2+f2k+...+ f4+f2)
m - n = xp∙ (fp+2 - fp +1)+ xp - 1∙ (fp + 1-fp)+...+x2k+2∙ (f2k+4 - f2k+3)+ (f2k+2 - f2k+1)+ ...+
(f2-f1) = xp∙ fp + xp - 1∙ fp-1 +...+ x2k+2f2k+2 + f2k+1= d, conform proprietăţii (3).
Unicitatea se poate demonstra, aplicând formulele (5), (6) în sens invers
(formula (5) corespunde cazului în care n se termină cu 0, formula (6), pentru
cazul în care n nu se termină cu 0).

Teoremă
Dacă n şi m, numărul de pietre din prima, respectiv cea de a doua grămadă nu
formează o pereche distinsă, atunci primul jucător are strategie sigură de câştig
(câştigă dintr-o singură mutare, sau poate aduce jocul printr-o singură mutare
într-o situaţie în care (n, m) formează o pereche distinsă.

Schiţa de demonstraţie
1. Dacă n = m sau n = 0 primul jucător câştigă dintr-o singură mutare.
2. Dacă 0 < n < m, determinăm perechea distinsă (n, p) şi perechea distinsă (a,
b) astfel încât b - a = m - n.
Dacă p < m, atunci se poate trece cu o singură mutare de la perechea (n, m) la
perechea distinsă (n, p).
Dacă p > m, deducem p - n > b - a = m - n, deci perechea distinsă (n, p) este
"mai mare" decât perechea distinsă (a, b), deci p > m, a > n. Deducem n - a = m
- b, deci dintr-o singură mişcare putem trece la perechea distinsă (a, b).
3. Dacă perechea (n, m) este distinsă, după orice mişcare ea va înceta să mai fie
distinsă.

Ce este jocul NIM?


Pentru început ne vom familiariza cu jocul clasic NIM:
Se consideră N grămezi de pietre. Doi jucători, vor ridica alternativ oricâte pietre
dintr-o singură grămadă. Câștigătorul este cel care ia ultima piatră.

În rezolvare distingem mai multe cazuri:

 Pentru cazul trivial în care numărul de grămezi este egal cu 1, primul


jucător are, evident, strategie de câștig, el putând lua toate pietrele din
grămadă.
 Dacă numărul de grămezi este egal cu 2, primul jucător are strategie de
câştig atunci când numărul de pietre din prima grămadă este diferit de
numărul de pietre din cea de-a doua, strategia lui fiind cea de a aduce tot
timpul grămada mai mare la numărul de pietre al grămezii mai mici, şi cum
jocul este finit, înseamnă că primul jucător o să aducă jocul în starea (0,
0).
 Dacă numărul de grămezi este mai mare decât doi, strategia se complică şi
nu se mai observă cu "ochiul liber". Stările câștigătoare pentru mai multe
Lectia 5. Strategii de joc. Jocul NIM

grămezi sunt acele stări pentru care suma XOR a numerelor de pietre din
grămezi este diferită de 0, restul stărilor fiind de pierdere.
De exemplu, dacă avem 4 grămezi cu 1, 3, 5, respectiv 7 pietre:
 O
 OOO
 OOOOO
 OOOOOOO

Atunci vom avea:

 1 = (0001)2
 3 = (0011)2
 5 = (0101)2
 7 = (0111)2
Efectuând XOR (operatorul ^ în C/C++) între reprezentările binare ale numerelor,
obţinem 0 = (0000)2. Conform propoziţiei de mai sus, această stare este de pierdere.
Să demonstrăm cele afirmate. Dintr-o poziţie cu suma XOR egală cu 0, pentru orice
mutare ajungem evident la o poziţie cu suma XOR diferită de 0, pentru că luând dintr-o
grămadă un număr x de pietre, suma XOR corespunzătoare noii stări, pe poziţia bitului
de 1 cel mai din dreapta în reprezentarea lui x, va avea valoarea 1.
Mai rămâne de demonstrat că din orice poziţie cu suma XOR diferită de 0 putem trece
printr-o mutare convenabilă într-o poziție cu suma XOR egală cu 0. Căutăm o grămadă al
cărui număr de pietre are bitul 1 pe poziţia celei mai mari puteri a lui 2 care apare în
suma XOR. Fie x valoarea sumei XOR a tuturor grămezilor şi y numărul de pietre din
grămada găsită mai devreme.
O mutare "câştigătoare" este extragerea din grămada găsită care are y pietre a y -
(x XOR y) pietre (x XOR y este mai mic decât y pentru că în y se anulează bitul cel mai
semnificativ al lui x). Atunci noua sumă XOR va fi egală cu 0.

De exemplu:

 4 ^ 8 ^ 17 = (00100)2 ^ (01000)2 ^ (10001)2 = (11101)2 = 29.

Mutarea câştigătoare constă în a lua din cea de-a treia gramadă un număr de pietre egal
cu:

 17 - (17 ^ 29) = 17 - 12 = 5 = (00101)2.


După acest pas grămezile vor avea 4, 8, 12 pietre. Ne aflăm astfel într-o stare cu
suma XOR egală cu 0.

Aplicaţii ale strategiei NIM


Exemplificăm în continuare câteva probleme în care se foloseşte strategia jocului NIM.
Problema 1
Pe o tablă de şah, care are N x M căsuţe, sunt plasaţi pe prima linie N pioni albi şi
pe ultima linie N pioni negri. Fiecare dintre cei doi jucători poate muta un singur pion,
care îi aparţine, un număr strict pozitiv de căsuţe în sus sau în jos, astfel încât să nu
ajungă vreun pion alb să fie mai jos decât pionul negru de pe aceeaşi coloană. Pierde
jucătorul care nu mai poate muta.

Soluţie
Lectia 5. Strategii de joc. Jocul NIM

Această problemă este o deghizare a jocului NIM, numărul de pătrăţele libere între pionul
alb şi pionul negru de pe coloana i putând fi considerat numărul de pietre din
grămada i. Singura diferenţă este că se pot adăuga pietre la grămadă (existând
posibilitatea mutării înapoi). Această problemă se rezolvă uşor, jucătorul care are
strategie de câştig putând evita asemenea mutări. O astfel de mutare poate fi utilă
numai pentru jucătorul care este într-o poziţie de pierdere. Când jucătorul care nu are
strategie de câştig mută înapoi x căsuţe, celălalt jucător va muta pionul propriu de pe
aceeaşi coloanã cu x căsuţe în faţă, astfel ajungându-se la aceeaşi stare cu cea existentă
cu două mutări anterior (considerând diferenţa poziţiilor).

Problema 2 (Baraj ONI 1997)


Pe o linie sunt plasate la coordonate întregi 2 x N piese roşii şi albastre. Fiecare
piesă roşie poate fi mutată în dreapta oricâte poziţii astfel încât să nu sară peste o piesă
albastră, iar piesele albastre pot fi mutate oricâte poziţii la stânga astfel încât să nu
depăşească vreo piesă roşie. Piesele vor alterna: roşu, albastru, roşu, albastru etc.
Pierde jucătorul care nu mai poate muta.

Soluţie
Această problemă poate fi, de asemenea, redusă la jocul NIM. Diferenţele poziţiilor
perechilor de piese roşii şi albastre consecutive constituie numărul de pietre al
grămezilor din jocul NIM.

Problema 3: Nim Game - Give Away! (El Judge)


Se consideră N grămezi de pietre, jucătorii mută alternativ, fiecare jucător extrăgând
oricâte pietre dintr-o singură grămadă. Cel care ia ultima piatră pierde jocul.

Soluţie
Strategia acestui joc este similară cu cea aplicată în jocul NIM cu câteva mici diferenţe.
Jucătorul care are strategie de câştig în poziţia curentă în cadrul jocului NIM face aceeaşi
mutare pe care ar face-o în cazul jocului NIM, exceptând cazul în care această mutare
lasă doar grămezi cu o singură piatră şi numărul acestor grămezi este par. În această
situaţie, dacă ar trebui să distrugă o grămadă de x pietre, jucătorul poate lua x - 1, iar
dacă ar trebui să lase o singură piatră din grămada actuală, poate lua întreaga grămadă.
Astfel, numărul de grămezi rămase va fi impar şi el nu va face ultima mutare.

Numerele Sprague-Grundy
Jocurile care prezintă interes pentru jucători sunt acelea care necesită
examinarea unui număr foarte mare de stări pentru determinarea strategiei de câştig,
deoarece în caz contrar câştigătorul s-ar cunoaşte chiar de la început. Spre deosebire de
aceştia, matematicienii sau informaticienii sunt interesaţi de determinarea unor strategii
pentru astfel de jocuri. Toate jocurile imparţiale cu doi jucători cu informaţie totală pot fi
reduse la jocul NIM care se joacă cu nişte grămezi virtuale, în care mutările posibile sunt
extragerea oricâtor pietre dintr-o grămadă sau adăugarea oricâtor pietre la o grămadă
(aşa cum am menţionat anterior, adăugarea de pietre la o grămadă nu complică analiza
jocului).
Afirmaţia anterioară constituie un rezultat al Teoriei Sprague-Grundy. Roland Percival
Sprague (1936) şi Patrick Michael Grundy (1939) sunt doi matematicieni care s-au
ocupat, independent, de teoria jocurilor imparţiale.

În continuare, considerăm următorul enunţ:

Se consideră un graf aciclic care conţine în noduri câţiva pioni, jucătorii alternează la
mutare şi fiecare poate muta câte un pion pe un arc care iese din nodul în care este
situat pionul. Pierde jucătorul care nu mai poate muta.
Lectia 5. Strategii de joc. Jocul NIM

Întrucât graful este aciclic, jocul este finit şi are întotdeauna un câştigător.
Practic, acest joc este suma unor jocuri, mai precis suma a mai multor jocuri cu un
singur pion pe graful aciclic.
Jocul cu un singur pion poate fi analizat destul de uşor, fiecare nod al grafului
putând fi colorat cu alb sau negru după cum există sau nu strategie de câştig dacă în
nodul curent ar fi poziţionat pionul. Această colorare poate fi realizată uşor dacă se
porneşte de la nodurile fără urmaş şi la fiecare pas se colorează câte un nod ai cărui
urmaşi sunt deja coloraţi. Orice joc imparţial poate fi redus la un joc cu un singur pion.
Nodurile sunt poziţiile jocului şi arcele grafului sunt mutările posibile din fiecare poziţie.
Jocul iniţial poate fi şi el transformat, dar numărul de noduri creşte foarte mult
(pentru N pioni şi M noduri, numărul de noduri din jocul transformat este NM) şi nu este
practic să colorăm graful rezultat. Folosind teoria dezvoltată de Sprague şi Grundy,
putem reduce complexitatea analizei jocului cu N pioni la complexitatea analizei jocului
cu un pion.
Vom introduce funcţia mex cu semnificaţia: mex(S) este elementul minimal
natural care nu aparţine mulţimii S. Pentru fiecare nod x al grafului aciclic considerat,
vom calcula valoarea funcţiei gx = mex(gx1, gx2, …, gxk), unde x1, x2, …, xk sunt
urmaşii nodului x în graf. Pentru nodurile fără urmaşi gx = 0.
Analog jocului cu un singur pion, graful poate fi etichetat din aproape în aproape,
pornind de la nodurile fără urmaşi. Observăm că, dacă gx = 0, în jocul cu un singur pion
situat în nodul x nu avem strategie de câştig, iar dacă gx este diferit de 0 avem strategie
de câştig. Restul informaţiei ne ajută la determinarea unei strategii pentru jocul
cu N pioni. Observăm că putem reduce acest joc la jocul NIM în care grămada virtuală
asociată pionului i are un număr de pietre egal cu valoarea g a nodului în care este
situat pionul i.
De ce este acest joc echivalent cu jocul NIM?
Aşa cum la NIM puteam lua oricâte pietre dintr-o grămadă, aici putem muta pionul dintr-
un nod cu valoarea g într-un nod astfel încât noua valoare pentru pionul i poate fi orice
număr de la 0 la g - 1. Prin urmare, pentru a verifica dacă suntem într-o poziţie de
câştig în jocul cu pionii, putem aplica strategia jocului NIM şi obţinem că suntem într-o
poziţie de câştig dacă suma XOR a numerelor din nodurile ocupate de cei N pioni este
diferită de 0.

Această sumă se numeşte funcţia Sprague-Grundy: .

Problema se rezolvă acum uşor efectuând o sortare topologică a nodurilor grafului aciclic
şi numerotând nodurile folosind funcţia mex.

Aplicaţii ale numerelor Sprague-Grundy


În continuare, să studiem alte probleme ce se pot rezolva cu numerele Sprague-Grundy.

Problema 4: Joc (Bursele Agora 2003/2004, Runda 13)


Să se verifice existenţa unei strategii de câştig pentru un joc similar cu NIM în care
se poate lua dintr-o grămadă o piatră sau un număr prim de pietre.

Dacă determinăm valorile Sprague-Grundy pentru grămezi de dimensiuni mici putem


observa că se repeta o succesiune de numere: 0 1 2 3 0 1 2 3 ... Putem demonstra
prin inducţie că această secvenţă se va repeta la nesfârşit. Pentru o grămadă de
dimensiune n, valoarea asociată va fi n modulo 4. Pentru 0 ≤ n ≤ 3 afirmaţia este
adevărată. Vom presupune afirmaţia adevărată pentru toate valorile m < n. Să
demonstrăm acum că este adevărată şi pentru n. Deoarece putem lua din n pietre una,
două sau trei pietre, mai rămâne valoarea n modulo 4 care nu este eliminată încă din
valorile potenţiale asociate grămezii de dimensiune n. Vom arăta în continuare că
această valoare nici nu va fi eliminată. Eliminarea ei ar însemna că putem lua din n un
Lectia 5. Strategii de joc. Jocul NIM

număr p de pietre şi atunci din (n - p) modulo 4 = n modulo 4, am avea: p modulo 4


= 0, dar p este un număr prim, deci valoarea Sprague-Grundy asociată unei grămezi de
dimensiune n este n modulo 4.

Problema 5: Stone game (El Judge)


Se consideră K grămezi cu n1, n2, ..., nK pietre fiecare. Când este rândul său, un
jucător poate lua dintr-o gramadă 2m pietre. Jucătorul care ia ultima piatră câştigă.
Restricţii: K ≤ 50, ni ≤ 10200.

Soluţie
Să determinăm valorile Sprague-Grundy pentru grămezi mici:
0 : 0; 1 : 1; 2 : 2; 3 : 0; 4 : 1; 5 : 2; 6 : 0
Observăm şi aici secvenţa repetitivă 0 1 2 0 1 2, deci am putea trage concluzia că
valoarea Sprague-Grundy asociată unei grămezi de dimensiune n este n modulo 3.
Această afirmaţie este adevarată şi urmează aceeaşi demonstraţie ca în cazul problemei
anterioare, iar restul modulo 3 pentru un număr cu 200 de cifre este simplu de găsit
determinând suma cifrelor numărului.

Problema 6: Stone game II (El Judge)


Se consideră K grămezi de pietre cu n1, n2 ..., nK pietre. Un jucător poate lua
dintr-o grămadă la mutarea lui un număr pozitiv de pietre, dar nu mai mult de jumătate
din pietrele din grămadă. Jucătorul care nu mai poate muta pierde. Restricţii: K ≤ 50,
ni ≤ 100000.

Soluţie
Numărul 100000 nu este foarte mare şi valorile Sprague-Grundy pot fi determinate off-
line şi incluse în programul nostru sub formă de constante. Putem scrie pentru valori mici
secvenţa Sprague-Grundy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 1 0 2 1 3 0 4 2 5 1 6 3 7
Pentru n impar valoarea asociată este aceeaşi cu valoarea asociată lui n/2, şi
pentru n par valoarea asociată este n/2. Acest lucru se poate demonstra prin inducţie
matematică.

Problema 7: Sticks (CEOI 2000)

Se consideră n (n ≤ 10) rânduri de beţe pe o masă, cu Si (Si ≤ 10) beţe aliniate pe


fiecare rând şi doi jucători. Beţele de pe rândul i sunt numerotate secvenţial de
la 1 la Si. Cei doi jucători mută alternativ. Fiecare mişcare constă în eliminarea a unu,
două sau trei beţe de pe acelaşi rând. Beţele trebuie sã fie numerotate secvenţial, adică
să fie consecutive. De exemplu, un rând are 10 beţe şi primul jucător elimină
beţele 4, 5, 6, deci vor rămâne numai beţele 1, 2, 3, 7, 8, 9, 10. Al doilea jucător poate
lua la rândul său beţele 1, 2, 3, dar nu beţele 3, 7, 8 pentru că acestea nu sunt
numerotate consecutiv (bineînţeles că există şi alte mutări valide). Câştigă jucătorul care
ia ultimul băţ de pe masă.

Soluţie
Problema generală are o soluţie ingenioasă care ţine seama de parităţile
rândurilor, dar la această problemă, datorită mărginirii lui Si (Si ≤ 10) nu este necesar
să fim ingenioşi. Restricţia Si ≤ 10 ne ajută prin faptul cã numărul total de poziţii (dacă
jucăm pe o singură gramadă), este 210. Vom reprezenta o poziţie printr-un întreg, iar
dacă acel întreg are în codificarea lui binară pe poziţia i un bit de 1 înseamnă că el
reprezintă un rând de beţe care conţine în el băţul numerotat cu i. Este uşor de realizat
un graf aciclic al mişcărilor pentru un rând (graful este aciclic pentru că la fiecare mutare
luăm beţe din configuraţie). Numerotăm fiecare poziţie cu numerele Sprague-Grundy, şi
acum problema deciderii dacă suntem sau nu într-o poziţie câştigătoare devine banală.
Lectia 5. Strategii de joc. Jocul NIM

În problema iniţială trebuia să jucăm împotriva calculatorului şi să câştigăm. Putem


realiza aceasta folosind mutarea câştigătoare prezentată la jocul NIM.

sticks.h
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

#define REP( i, n ) \
for ( int i = 0; i < (n); i++ )
#define ALL( c ) (c).begin(), (c).end()
namespace sticks {
static const int
MAXN = 10,
MAXVAL = 10;
int SG[1 << MAXVAL];
vector< int > V;
void calc_SG() {
/* Sprague-Grundy */
SG[0] = 0; // P-position
REP( i, (1 << MAXVAL) ) {
if ( !i ) continue;
vector< int > nxt;
REP( j, 3 )
REP( k, MAXVAL ) {
int mask = ((1 << (j+1)) - 1) << k;
if ( (i & mask) == mask )
nxt.push_back( SG[i - mask] );
}
sort( ALL( nxt ) );
nxt.erase( unique( ALL( nxt ) ), nxt.end() );
int ans = 0;
while ( ans < nxt.size() && nxt[ans] == ans )
ans++;
SG[i] = ans;
}
}

vector< int > getPiles( int& player ) {


calc_SG();
int n, x;
cin >> n;
while ( n-- ) {
cin >> x;
V.push_back( (1 << x) - 1 );
}
cin >> player;
return V;
}
void putMove( int pile, int lo, int hi ) {
printf( "Human remove [%d,%d] from pile %d\n", lo, hi, pile );
pile--; lo--; hi--;
assert( pile >= 0 && pile < V.size() );
assert( lo <= hi );
int mask = (1 << (hi - lo + 1)) - 1;
Lectia 5. Strategii de joc. Jocul NIM

mask = (mask << lo);


assert( (V[pile] & mask) == mask );
V[pile] -= mask;

if ( count( ALL( V ), 0 ) == V.size() ) {


printf( "You win!!!\n" );
exit( 0 );
}
}

void getMove( int& pile, int& lo, int& hi ) {


int sgval = 0;
REP( i, V.size() )
sgval ^= SG[ V[i] ];
if ( sgval ) { // find winning move
// You loose
// printf( "You loose stupid!!!\n" );
// exit( 0 );
int leftcol = 31 - __builtin_clz( sgval );
REP( i, V.size() )
if ( SG[ V[i] ] & (1 << leftcol) ) {
vector< int > nxt;
REP( j, 3 ) // sticks to remove
REP( k, MAXVAL ) { // first stick
int mask = ((1 << (j+1)) - 1) << k;
if ( (V[i] & mask) == mask ) {
int sgnxt = (sgval ^ SG[ V[i] ]) ^ SG[ V[i] - mask ];
if ( sgnxt == 0 ) {
lo = k;
hi = k + j;
pile = i;
goto finish;
}
}
}
finish:;
break;
}

} else {
REP( i, V.size() )
if ( V[i] > 0 ) {
pile = i;
lo = hi = __builtin_ctz( V[i] );
}
}

int mask = (1 << (hi - lo + 1)) - 1;


mask = (mask << lo);
assert( (V[pile] & mask) == mask );
V[pile] -= mask;

// 1-based
pile++; lo++; hi++;
printf( "Machine remove [%d,%d] from pile %d\n", lo, hi,
pile );

if ( count( ALL( V ), 0 ) == V.size() ) {


Lectia 5. Strategii de joc. Jocul NIM

printf( "You loose stupid!!!\n" );


exit( 0 );
}
}

};

using sticks::getPiles;
using sticks::putMove;
using sticks::getMove;
Solutie:

#include "sticks.h"
#include <cstdio>
#include <algorithm>
#include <vector>

using namespace std;

#define REP( i, n ) \
for ( int i = 0; i < (n); i++ )

#define ALL( c ) (c).begin(), (c).end()

const int
MAXN = 10,
MAXVAL = 10;
int N;
int player;
vector< int > V;
int SG[1 << MAXVAL];
int main() {
/* Sprague-Grundy */
SG[0] = 0;
REP( i, (1 << MAXVAL) ) {
if ( !i ) continue;

vector< int > nxt;


REP( j, 3 )
REP( k, MAXVAL ) {
int mask = ((1 << (j+1)) - 1) << k;
if ( (i & mask) == mask )
nxt.push_back( SG[i - mask] );
}
sort( ALL( nxt ) );
nxt.erase( unique( ALL( nxt ) ), nxt.end() );
int ans = 0;
while ( ans < nxt.size() && nxt[ans] == ans )
ans++;
SG[i] = ans;
}
V = getPiles( player );
for (;;) {
int pile, lo, hi;
if ( player ) {
getMove( pile, lo, hi );
pile--; lo--; hi--;
} else {
Lectia 5. Strategii de joc. Jocul NIM

int sgval = 0;
REP( i, V.size() )
sgval ^= SG[ V[i] ];
if ( sgval ) {
int leftcol = 31 - __builtin_clz( sgval );
REP( i, V.size() )
if ( SG[ V[i] ] & (1 << leftcol) ) {
REP( j, 3 )
REP( k, MAXVAL ) {
int mask = ((1 << (j+1)) - 1) << k;
if ( (V[i] & mask) == mask )
{
int sgnxt = (sgval ^ SG[ V[i] ]) ^ SG[ V[i] - mask ];
if ( sgnxt == 0 ) {
lo = k;
hi = k + j;
pile = i;
goto finish;
}
}
}
finish:;
break;
}

} else {
REP( i, V.size() )
if ( V[i] != 0 ) {
lo = hi = __builtin_ctz( V[i] );
pile = i;
break;
}
}
putMove( pile + 1, lo + 1, hi + 1 );
}
int mask = (1 << (hi - lo + 1)) - 1;
mask <<= lo;
assert( (V[pile] & mask) == mask );
V[pile] -= mask;

player ^= 1;
}
return 0;
}

Problema 8: Joc (Bursele Agora 2006)

Doi participanţi mănâncă alternant din nişte tablete de ciocolată după următoarele
reguli:
• taie o tabletă în două, tăietura trebuie să fie paralelă cu una din laturile tabletei şi
trebuie să nu taie pătrăţelele de ciocolată;

• pot să rupă şi să mănânce orice linie sau coloană de pătrăţele care nu se află pe
marginea tabletei;
• pot să rupă şi să mănânce toate patrăţelele de pe marginea tabletei, cu condiţia ca
tableta rămasă să aibă cel puţin dimensiunea 1 × 1.
Lectia 5. Strategii de joc. Jocul NIM

Niciuna dintre aceste trei mutări nu poate fi efectuată asupra unei tablete de
dimensiune 1 × 1. Pierde jucătorul care nu mai poate efectua nicio mutare. În fişierul de
intrare se va afla numărul N (1 ≤ N ≤ 100) de tablete, iar pe următoarea linie vor
fi N perechi de numere întregi care reprezintă dimensiunile tabletelor. În fişierul de ieşire
se va afla un singur număr întreg reprezentând numărul mutărilor câştigătoare pentru
primul jucător.
Soluţie
Pentru această problemă vom calcula matricea SGi,j care reprezintă valoarea Sprague-
Grundy asociată unei tablete de dimensiuni (i, j). Să vedem care este recurenţa care
va satisface elementele matricei SG:

Acum, pentru a calcula numărul de mutări câştigătoare efectuăm asupra fiecărei tablete
din fişierul de intrare toate mutările posibile (care sunt cel mult 4 * 100 + 1) şi facem
suma XOR a valorilor Sprague-Grundy pentru restul tabletelor neimplicate în mutare şi a
tabletelor rezultate din mutare. Pentru a calcula SGi,j trebuie sã parcurgem cel mult 2 *
i + 2 * j + 1 valori obţinute. Astfel, algoritmul de determinare a valorilor
matricei SG are ordinul de complexitate O(N3). Complexitatea algoritmului care determină
numărul de mutări câştigătoare este O(N2).

Probleme suplimentare
Joc3
Gigel si Andrei au N saci cu pietre pretioase numerotati de la 1 la N. Pentru ca nu vor sa imparta
pietrele intre ei, au hotarat sa joace un joc iar castigatorul sa ia toate pietrele. Jocul consta in
efectuarea alternativa a unor mutari. O mutare consta in selectarea unor pietre dintr-un
sac i (1 ≤ i < N) si mutarea acestora in sacul i+1. Jucatorul care nu mai poate efectua nici o
mutare (atunci cand toate pietrele sunt asezate in ultimul sac) pierde jocul.

Cerinta
Stiind atat numarul de saci si configuratia acestora, cat si faptul ca Gigel va efectua prima mutare
determinati, daca exista, o strategie de castig pentru el.

Date de intrare
Pe prima linie a fisierului joc3.in se va afla N, numarul de saci. Urmeaza N linii, pe linia i aflandu-
se numarul de pietre pretioase din sacul i.

Date de iesire
In cazul in care Gigel nu are strategie de castig fisierul de iesire joc3.out va contine pe prima linie
valoarea -1. Altfel, afisati pe prima linie numerele p si q ce codifica mutarea initiala pe care ar
trebui sa o efectueze Gigel pentru a castiga jocul (p este numarul sacului, iar q numarul de pietre).
In cazul in care exista mai multe mutari initiale ce ar putea duce la castigarea sigura a jocului,
afisati mutarea care are p minim. Daca totusi mai sunt cazuri de egalitate, afisati mutarea
cu q minim.

Restrictii si precizari
 1 ≤ N ≤ 100.000
Lectia 5. Strategii de joc. Jocul NIM

 0 ≤ numarul de pietre dintr-un sac ≤ 10.000

Exemple
joc3.in joc3.out
5 2 2
2
5
4
3
1

Explicatie
Efectuand aceasta mutare Gigel va castiga daca va continua sa joace perfect. Nu exista alta
mutare cu p sau q mai mic.
joc3.in joc3.out
5 -1
0
0
0
0
10000

Explicatie
Cum toate pietrele sunt asezate in ultimul sac, Gigel nu poate efectua vreo mutare.

Solutie:

#include <fstream>
using namespace std;
ifstream fin("joc3.in");
ofstream fout("joc3.out");
int n, a, xo;
int v[100001];
int main()
{
fin >> n;
for (int i = 1; i < n; ++i)
{
fin >> v[i];
if ((n - 1) % 2 == i % 2) xo ^= v[i];
}
if (!xo) {fout << -1; return 0;}
for (int i = 1; i < n; ++i)
{
if ((n - 1) % 2 == i % 2)
{
if ((v[i] ^ xo) < v[i])
{fout << i << " " << v[i] - (v[i] ^ xo);
return 0;
}
else
{
if (v[i] + v[i - 1] >= (xo ^ v[i]))
{
fout << i - 1 << " " << (xo ^ v[i]) - v[i];
return 0;
}
}
Lectia 5. Strategii de joc. Jocul NIM

}
return 0;
}

Aiacujoc
În drumul lor către oraşul Zalău, Bulănel şi Bulăniţa au hotărât să joace un joc pentru a alunga
plictiseala.Cei doi au la dispoziţie un grid cu N linii (numerotate de la 1 la N) şi M coloane
(numerotate de la 1 la M). Bulănel începe jocul prin plasarea unui pătrat pe o celulă a gridului.
Scopul jocului este acoperirea gridului înaintea celuilalt jucător. La fiecare pas, un jucător alege o
direcţie (nord, est, sud, vest) si extinde figura rectangulară în direcţia respectivă cu maxim K linii
(dacă direcţia aleasă a fost nord sau sud) sau maxim K coloane (dacă direcţia aleasă a fost est sau
vest). La nici un moment al jocului, nu se poate extinde figura în afara gridului. Jucătorul care nu
mai poate extinde figura în nicio direcţie este declarat pierzător. După ce Bulănel plasează pătratul
iniţial, Bulăniţa e cea care face prima extindere.

De exemplu, dacă ar juca pe un grid de N = 3 linii şi M = 5 coloane şi ar alege K = 3, jocul s-ar putea
desfăşura în felul următor:

Pasul 1: Bulănel plasează pătratul pe Pasul 2: Bulăniţa extinde figura Pasul 3: Bulănel extinde figura cu 1 linie în

linia 2, coloana 5 cu 2 coloane în vest. nord.

Pasul 4: Bulăniţa extinde figura Pasul 5: Bulănel extinde figura Pasul 6: Bulăniţa extinde figura

cu 1 linie în sud. cu 1 coloană în vest. cu 1 coloană în vest.

Bulănel pierde jocul acesta din cauză că nu mai poate extinde figura în nici o direcţie. Totuşi,
Bulănel ar fi putut câştiga jocul dacă ar fi făcut o serie diferită de mişcări (de exemplu, dacă ar fi
extins figura cu 2 coloane în vest în loc de 1, în pasul 5) sau dacă ar fi plasat pătratul iniţial pe o
altă poziţie.

Cerinţă
Cei doi hotărăsc să joace mai multe jocuri. Ajutaţi-l pe Bulănel să afle, pentru fiecare joc, numărul
de poziţii în care poate plasa pătratul iniţial astfel încât să aibă strategie de câştig, adică să poată
câştiga indiferent de mutările Bulăniţei.

Date de intrare
Fişierul de intrare aiacujoc.in conţine pe prima linie numărul natural T, reprezentând numărul de
jocuri pe care Bulănel şi Bulăniţa o să-l joace. Pe fiecare din următoarele T linii, se află câte trei
numerele naturale care definesc un joc: numărul natural N, reprezentând numărul de linii ale
gridului, urmat de numărul natural M, reprezentând numărul de coloane ale gridului, urmat de
numărul natural K, reprezentând numărul maxim de linii sau de coloane cu care un jucător poate
extinde figura la un anumit pas.
Lectia 5. Strategii de joc. Jocul NIM

Date de ieşire
Fişierul de ieşire aiacujoc.out va conţine T linii. Pe fiecare linie i, se va afla câte un număr natural
care reprezintă numărul de poziţii de pe grid unde Bulănel poate plasa pătratul iniţial, care îi
asigură lui Bulănel strategie câştigătoare pentru al i-lea joc.

Restricţii
 Pentru toate testele, 1 ≤ T ≤ 10.
 Pentru teste în valoare de 5 puncte, N = 1, 1 ≤ M ≤ 20, K ≥ max(N, M).
 Pentru alte teste în valoare de 5 puncte, 1 ≤ N, M ≤ 20, K ≥ max(N, M), N şi M au parităţi
diferite.
 Pentru alte teste în valoare de 10 puncte, 1 ≤ N, M ≤ 20, K ≥ max(N, M).
 Pentru alte teste în valoare de 30 de puncte, 1 ≤ N, M ≤ 1 000, K ≥ max(N, M).
 Pentru alte teste în valoare de 10 de puncte, 1 ≤ N, M ≤ 1 000 000, K ≥ max(N, M).
 Pentru alte teste în valoare de 20 de puncte, 1 ≤ N, M, K ≤ 1 000 000.
 Pentru alte teste în valoare de 10 de puncte, 1 ≤ N, M ≤ 1 000 000 000, 1 ≤ K ≤ 1 000 000.
 Ambii jucători joacă optim ceea ce înseamnă că nu fac greşeli, anticipează mişcările
adversarului, iar dacă există o strategie de mişcări care să-i conducă spre câştig
atunci o vor folosi.
 Problema va fi evaluată pe teste în valoare de 90 de puncte.
 Exemplele vor reprezenta teste în valoare de 10 ("puncte din oficiu") şi vor fi cu
feedback.

Exemplu
aiacujoc.in aiacujoc.out
2 5
3 5 5 320
88 200 200

2 7
3 5 3 680
88 200 56

Explicaţie
Primul exemplu
Pentru primul joc, gridul are dimensiunile N=3, M=5. Un jucător poate extinde figura cu
maxim K=5 linii sau coloane. Poziţiile care îi asigură lui Bulănel strategie de câştig sunt (1;2), (1;4),
(2;3), (3;2), (3;4).

Pentru al doilea joc, gridul are dimensiunile N=88, M=200. Un jucător poate extinde figura cu
maxim 200 de linii sau coloane. Sunt 320 de poziţii care conduc la câştig.

Al doilea exemplu
Pentru primul joc, gridul are dimensiunile N=3, M=5. Un jucător poate extinde figura cu
maxim K=3 linii sau coloane. Poziţiile care îi asigură lui Bulănel strategie de câştig sunt (1;2), (1;4),
(2;1), (2;3), (2;5), (3;2), (3;4).

Pentru al doilea joc, gridul are dimensiunile N=88, M=200. Un jucător poate extinde figura cu
maxim 56 de linii sau coloane. Sunt 680 de poziţii care conduc la câştig.
Soluție:
#include <bits/stdc++.h>
using namespace std;
ifstream fin("aiacujoc.in");
ofstream fout("aiacujoc.out");
int t,n,m,k,i,x;
long long a[1<<21],b[1<<21];
int main()
{
fin>>t;
while(t--)
{
fin>>n>>m>>k;
for(i=0;i<(1<<21);++i) a[i]=b[i]=0;
Lectia 5. Strategii de joc. Jocul NIM

for(i=0;i<=k;++i)
{
if(i<n)
{
x=i^((n-i-1)%(k+1));
a[x]+=1+(n-i-1)/(k+1);
}
if(i<m)
{
x=i^((m-i-1)%(k+1));
b[x]+=1+(m-i-1)/(k+1);
}
}
long long sol=0;
for(i=0;i<(1<<21);++i) sol+=1LL*a[i]*b[i];
fout<<sol<<'\n';
}
return 0;
}

Cartonase
Miruna are N cartonase pe care le-a asezat in linie dreapta pe masa. Fiecare cartonas are o fata
colorata cu rosu, iar cealalta cu albastru. Miruna si fratiorul ei se gandesc la urmatorul joc:
 O mutare valida consta din alegerea unui cartonas cu fata rosie in sus si intoarcerea

lui. In plus, daca doreste, cel care e la mutare poate sa isi aleaga orice alt cartonas

(indiferent de culoarea fetei care este in sus) care se afla la stanga celui ales initial

si sa il intoarca.
 Cei doi copii efectueaza alternativ mutari valide.

 Castiga cel care efectueaza ultima mutare.

 Intotdeauna Miruna este cea care efectueaza prima mutare.

Cerinta
Stiind ca cei doi copii vor juca optim, se cere sa se stabileasca castigatorul pentru o configuratie
data a cartonaselor.

Date de intrare
Pe prima linie a fisierului de intrare cartonase.in se gaseste un numar intreg T, reprezentand numarul
de seturi de date de test ce vor urma. Pe fiecare dintre urmatoarele T linii se va afla un numar
intreg N, urmat de un spatiu, apoi de N caractere despartite prin cate un spatiu ce pot fi R sau A,
semnificand culorile fetelor cartonaselor care sunt in sus.

Date de iesire
Fisierul cartonase.out va contine T linii. Pe linia i (1 ≤ i ≤ T) va fi scris mesajul DA in cazul in care Miruna
este cea care castiga jocul descris pe linia i+1 in fisierul de intrare, respectiv mesajul NU in caz
contrar.

Restrictii
 1 ≤ T ≤ 20

 1 ≤ N ≤ 100

 Pentru 30% din teste 1 ≤ N ≤ 10

Exemplu
cartonase.in cartonase.out
Lectia 5. Strategii de joc. Jocul NIM

2 DA
3 A R R NU
3 R R R

Soluție:
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin("cartonase.in");
ofstream fout("cartonase.out");
int main()
{
int q,i,sum,n;char a;
fin>>q;
while(q--)
{
fin>>n;
sum=0;
for(i=1;i<=n;++i)
{
fin>>a;
if(a=='R') sum=i^sum;
}
if(sum) fout<<"DA\n";
else fout<<"NU\n";
}
return 0;
}
Probleme campion.edu.ro
# Nume ↓ Concurs ↓ Autor ↓ Grupă ↓ Dificultate ↑

1 cutie1 ONI 2012 Andrei Ciocan medie

2 joct .campion 2010 Prof. Marinel Şerban medie

3 joc13 OJI 2004 - medie

4 lipsa FII Competition 2011 Prof. Dr. Cornelius Croitoru toate

5 joc6 ONI 2007 Tiberiu Lucian Florea mare

6 color ONI 2004 Mugurel Ionuţ Andreica mare

7 neconex LOT SB 2011 Prof. Ionel-Vasile Piţ-Rada mare

8 gramezi1 Şansa de a deveni campion 2002 Prof. Nistor-Eugen Moţ mică

9 vector .campion 2006 Tiberiu Lucian Florea mare

10 cutii OMI Iaşi 2005 Prof. Cornelia Ivaşc medie

11 cartonase .campion 2007 Stud. Andrei Grigorean mare

12 pioni .campion 2007 Mircea Paşoi mare

13 jocv .campion 2009 Cătălin Tiseanu mare

14 graphgame .campion 2009 Stud. Vlad Tudose mare

15 connect3 .campion 2008 Stud. Adrian Airinei mare


Lectia 5. Strategii de joc. Jocul NIM

S-ar putea să vă placă și