|
Calculul combinarilor
Atat in domeniul matematicii cat si in cel al informaticii se gasesc adesea probleme care folosesc notiuni de combinatorica. In cazul optimizarii unei astfel de probleme, ne punem intrebarea 'cum calculam mai repede?'. In urmatoarele randuri voi prezenta raspunsul meu la aceasta intrebare.
Am
folosit 3 programe distincte pentru a calcula pe care apoi le-am
testat pentru diferite valori ale lui n si k. Pentru ca platforma Pascal
produsa de Borland nu suporta lucrul cu valori intregi peste 231
(longint), programele au fost compilate cu Free Pascal 0.9.2, pentru ca in
acesta se poate folosi tipul de date pe 64 biti qword (numere pozitive
pana la 264, cu o lungime de aproximativ 20 de cifre). Unul din
procedeele de optimizare a programelor a fost formula combinarilor
complementare:
, adica pentru orice k
> (n div 2) am calculat
. Astfel, pentru un n
natural, testul e maximal numai daca k =
n div 2.
Primul
program se bazeaza pe formula combinarilor, . Aceasta include calculul unor valori foarte mari si apoi
impartirea lor. Insa, inainte de a efectua inmultirile,
formula se poate simplifica: in loc sa calculeze n!, calculeaza numai produsul elementelor de la n-k+1 la n, apoi imparte la k!.
Astfel se poate calcula
pentru valori mai mari
ale lui n. De exemplu,
, mai mult decat poate stoca qword, dar prin simplificari
(kmax = 14), produsul numerelor de la 15 la 29 are 20 de cifre si
poate fi retinut in qword. La testele de viteza, programul a fost
eficient: pentru valori ale lui n cuprinse
intre 10 si 20 si k = n div 2,
timpul de executie a fost de 15-25ms, iar la valoarea maxima (n = 29, k = 14) nu a trecut de 30ms.
Al
doilea program consta in calcularea combinarilor cu o formula
recurenta: . Am folosit o procedura recursiva si asta implica
un timp de executie considerabil, in ciuda optimizarilor facute.
Pentru n
20 si k = n
div 2 programul a rulat in mai putin de 40ms, insa pentru 23
n
25 timpul de executie a ajuns la 100-140ms, iar
pentru n=29 si k=14, 1sec 780ms. Spre deosebire de primul program, acesta poate
calcula valoarea lui
pentru n>29 insa timpul de
executie devine mult prea mare. De exemplu, pentru n = 32 si k = 16,
afisarea rezultatului a durat aproximativ 13sec.
Cu
formula de recurenta avem posibilitatea de a implementa generarea triunghiului
lui Pascal cu o matrice patratica de ordin n, insa pentru
optimizare se pot folosi 2 vectori sau o matrice n2. Pentru n
29 si k = n
div 2, timpul de executie s-a incadrat in 30-40ms, dar valoarea maxima
pe care o poate lua n este 68 (k = 34), altfel
ar depasi 20 de cifre. In cazul testului cu n = 68
si k = 34, timpul de executie a fost tot 40ms.
Se observa ca cea mai rapida metoda de generare ramane construirea triunghiului lui Pascal, cu toate ca pe seturi mici de date se obtine un rezultat mai bun prin calcul direct.
Sistemul de evaluare a rulat pe un calculator cu procesor AMD Athlon XP Barthon 2500+, 768MB DDRAM. Sistemul de operare este Windows XP Professional SP2.