Problema 7 (Jocul vietii) a fost intr-o anumita masura un esec, mai
ales pentru cei care n-au trimis nici o sursa. Imi pare foarte rau si
promit ca pe viitor sa postez numai probleme cu teste "urate" gata
facute. Care a fost buba: aceasta problema nu are teste "urate", in
sensul ca orice configuratie cu N<=100 celule, ori se stabilizeaza in
maximum 16 iteratii, ori nu se stabilizeaza.
Totusi, iata algoritmul "destept", care are complexitate O(N^2) nu
O(N^3), lucru pe care l-am descoperit cu stupoare scriind programul.
Mai mult, raspunsul la intrebarea daca o colonie se stabilizeaza se
poate da in O(N).
Ideea de pornire este ca exista 2^N configuratii distincte de N
celule. Din acest motiv, conform principiului lui Dirichlet, este
evident ca dupa cel mult 2^N generatii configuratiile incep sa se
repete. Deci tot ce avem de facut este sa comparam generatia 2^N cu
generatia 2^N+1 si aflam daca (,) colonia se stabilizeaza.
Cum facem sa evoluam 2^N generatii ? Desigur, nu iterativ, ci evoluand
in salturi. Pentru aceasta, sa facem niste notatii: fie C[0]..C[N-1]
colonia originala si fie D[t][i] starea celulei i la momentul t.
Postulam ca:
D[2^k][i]=C[i-2^k] xor C[i+2^k] oricare k>=0
(aici indicii in C se iau modulo N).
Cu alte cuvinte, starea unei celule la momentul 1 este data de starea
originala a vecinilor ei; starea la momentul 8 este data de starea
originala a vecinilor ei de la 8 celule departare s.a.m.d.
Demonstratia se face prin inductie completa, desi dupa cum stim
programatorii se multumesc adesea cu inductia incompleta :) Deci:
1) Pentru k=0 propozitia este adevarata:
D[2^0][i]=C[i-2^0] xor C[i+2^0], adica D[1][i]=C[i-1] xor C[i+1],
ceea ce este adevarat.
2) Presupunem ca propozitia este adevarata pentru k si demonstram ca
este adevarata si pentru k+1. Pentru aceasta, remarcam ca generatia
de la momentul 2^(k+1) se obtine plecand din configuratia de la momentul
2^k si evoluand cu inca 2^k generatii:
C ----------------> D[2^(k+1)]
\ /
--> D[2^k] -->
Dar pentru 2^k iteratii afirmatia se verifica si putem scrie:
D[2^(k+1)][i]=D[2^k][i-2^k] xor D[2^k][i+2^k]
D[2^k][i-2^k]=C[i-2^k-2^k] xor C[i-2^k+2^k] = C[i-2^(k+1)] xor C[i]
D[2^k][i+2^k]=C[i+2^k-2^k] xor C[i+2^k+2^k] = C[i] xor C[i+2^(k+1)]
Din cele trei rezulta ca
D[2^(k+1)][i] = C[i-2^(k+1)] xor C[i] xor C[i] xor C[i+2^(k+1)]
= C[i-2^(k+1)] xor C[i+2^(k+1)] q.e.d.
Asadar pentru a calcula ceea ce ne intereseaza, si anume D[2^N],
scriem ca D[2^N][i]=C[i-2^N] xor C[i+2^N]. Nu va speriati ca 2^N are
vreo 30 de cifre cand N=100, pentru ca noua ne trebuie indicii (i-2^N)
modulo N si (i+2^N) modulo N, deci nu este nevoie de numere mari
(deocamdata).
D[2^N] se poate calcula in O(N) si astfel decidem daca (iar ,) colonia
se stabilizeaza. Presupunem ca se stabilizeaza - cum decidem in cat timp ?
Sa notam D[2^N] = S, configuratia in care incremeneste colonia. Acum
sa analizam sirul D[0]=C, D[1], D[2], ..., D[2^N].
Acest sir contine niste elemente diferite de S, apoi un sir de
elemente egale cu S, deoarece din clipa in care apare prima generatie
egala cu S, toate cele care ii urmeaza sunt egale cu S. Trebuie sa
aflam indicele primei generatii egale cu S. Aceasta se face prin
cautare binara. Intr-o prima faza, calculam D[2^(N-1)] si avem doua
variante:
- Daca D[2^(N-1)]=S, atunci colonia se stabilizeaza intr-un moment
anterior lui 2^(N-1);
- Daca D[2^(N-1)]<>S, atunci colonia se stabilizeaza intr-un moment
ulterior lui 2^(N-1);
Si asa mai departe. Teoretic, complexitatea se calculeaza astfel:
Numarul generatiei in care colonia se stabilizeaza este cuprins intre
0 si 2^N-1, deci are O(N) cifre. Adunarile pe asemenea numere se fac
in O(N).
Cautarea prin injumatatirea intervalului efectueaza log 2^N = N pasi.
Fiecare pas presupune o evolutie cu 2^tz generatii, care se face in
O(N), si eventual o adunare pe numere mari, deci inca O(N). Per total
O(N)*(O(N)+O(N))=O(N^2).
Cu "mica" observatie facuta la inceputul acestui mesaj, anume ca o
configuratie cu 100 celule se stabilizeaza in cel mult 16 iteratii,
putem reduce complexitatea la O(N). Dar asta-i alta poveste...
|
|