Inclus sau exclus... Principiul includerii și excluderiiDoru Popescu Anastasiu
Principiul includerii și excluderii este unul dintre cele mai cunoscute rezultate din matematică. Acest articol vă propune să analizați modul în care acest principiu poate fi folosit pentru rezolvarea unor probleme de algoritmică.
Enunțul principiului Fiind date nł2 mulțimi finite A1, A2, ..., An și notând cu card(A) numărul de elemente al mulțimii A, avem:
Demonstrația acestui rezultat se face prin inducție matematică (vezi [2] sau [3]).
Aplicația 1 Se dau p1, p2,... , pn (n Ł 10) numere prime distincte mai mici sau egale decât k (k < 1.000.000.000). Să se determine câte numere naturale mai mici sau egale cu k sunt divizibile cu unul din numerele p1, p2 ,... , pn. Exemplu Pentru n=3, p1=2, p2=3, p3=5, k=1000 se va afișa: 734
Soluție Considerăm mulțimile: Ai={piq | qÎN, piq Ł k}, iÎ{1, 2, ..., n}. Observăm că numărul căutat este r = card(A1ÈA2È...ÈAn), care este egal (conform principiului includerii și excluderii) cu:
Folosind card(Ai)= card({piq | qÎN, piq Ł k}) = [k/pi], iÎ{1, 2, ..., n}, card(AiÇAj) = card({pipjq | qÎN, pipjq Ł k}) = [k/(pipj)], i, jÎ{1, 2, ..., n} etc. se obține:
Un program care calculează acest număr este prezentat în continuare.
Listing APP1.PAS Program Aplicatia_1; var p:array[1..10] of Longint; n,i:Byte; k,r:Longint;
function suma(i:Byte):Longint; var s:Longint; v:array[1..10] of Byte; h,q,j:Byte; pr:Real; begin (* calculam cel de-al i-lea termen al sumei r, folosind metoda backtracking pentru a determina submultimile cu i elemente ale multimii {1,2,...,n} *) s:=0; h:=1; v[1]:=0; while h>0 do begin q:=0; while (q=0) and (v[h]<n) do begin Inc(v[h]); q:=1; if h>1 then if v[h]<=v[h-1] then q:=0 end; if q=0 then Dec(h) else if h=i then begin pr:=k; for j:=1 to i do pr:=pr/p[v[j]]; s:=s+Trunc(pr); end
else begin Inc(h); v[h]:=0 end end; suma:=s end; {suma}
Begin Write('n='); Readln(n); for i:=1 to n do begin Write('p[',i,']='); Readln(p[i]) end; Write('k='); Readln(k); r:=0; for i:=1 to n do if i mod 2=1 then r:=r+suma(i) else r:=r-suma(i); Writeln(r) End.
Aplicația 2 Se dă un număr natural nenul n Ł 14. Să se determine numărul permutărilor mulțimii {1,2,...,n} fără puncte fixe (adică permutări p = (p1, p2, ..., pn) cu proprietatea că pi č i, pentru orice i Î {1,2,...,n}). Exemplu Pentru n = 3 se va afișa: 2
Soluție Notând cu Ai mulțimea celor (n - 1)! permutări ale mulțimii {1,2,...,n} ce admit pe i ca punct fix, i Î {1,2,...,n}, folosind principiul includerii și excluderii deducem:
Fie B o submulțime cu k elemente a mulțimii {1,2, ...,n}. Atunci avem:
Fixând kŁn există astfel de submulțimi B. Rezultă:
Obținem astfel valoarea numărului căutat:
Programul care determină această valoare este următorul:
Listing APP2.PAS Program Aplicatia_2; var nr,p:Longint; n,i,j:Byte; Begin Write('n='); Readln(n); nr:=0; for i:=2 to n do begin {calculam raportul n!/i} p:=1; for j:=i+1 to n do p:=p*j; if i mod 2 =0 then nr:=nr+p else nr:=nr-p end; Writeln(nr) End.
Aplicația 3 Se dau numerele naturale n și k cu 1 Ł k Ł 9, k Ł n Ł 11. Să se determine câte numere compuse din n cifre există, care nu conțin decât cifrele 1, 2, ..., k, dar pe fiecare dintre acestea cel puțin o dată.
Exemplu Pentru n = 4 și k =3 se va afișa 36.
Soluție Numărul total de numere de n cifre ce se pot forma cu cele k cifre 1, 2, ..., k este egal cu numărul de funcții de la o mulțime cu n elemente la alta cu k elemente și deci egal cu kn. Fie acum Ai mulțimea numerelor de n cifre care nu-l conțin pe i, i Î {1,2,...,k}. Rezultă:
Deci numărul de numere compuse din n cifre, care nu conțin decât cifrele 1, 2, ..., k, dar pe fiecare dintre acestea cel puțin o dată este următorul:
Programul care calculează acest număr este următorul:
Listing APP3.PAS Program Aplicatia_3; var k,n,i:Byte; s:Longint; function comb(p,q:Byte):Longint; begin if (q=0) or (p=q) then comb:=1 else comb:=comb(p-1,q)+comb(p-1,q-1); end;
function prod(p,q:Byte):Longint; var i:Byte; pp:Longint; begin pp:=1; for i:=1 to q do pp:=pp*p; prod:=pp end;
Begin Write('n='); Readln(n); Write('k='); Readln(k); s:=0; for i:=0 to k do if i mod 2=0 then s:=s+comb(k,i)*prod(k-i,n) else s:=s-comb(k,i)*prod(k-i,n); Writeln(s) End.
Aplicația 4 Se dau n (n Ł 30000) puncte în plan P1, P2, ..., Pn și un număr natural k (k Ł 30000). Să se verifice dacă se pot construi k segmente cu ambele capete în mulțimea formată din punctele P1, P2, ..., Pn, astfel încât să nu se formeze nici un triunghi cu vârfurile în aceste puncte. Dacă nu există soluție se va afișa mesajul "IMPOSIBIL ". Dacă există soluție se va afișa o modalitate de construcție a segmentelor. Exemple Pentru n = 4 și k = 5 se va afișa: IMPOSIBIL Pentru n = 6 și k = 9 o soluție este: P1P3 P1P4 P1P5 P2P3 P2P4 P2P5 P6P3 P6P4 P6P5
Soluție Pentru a rezolva această problemă avem nevoie de rezultatul următor:
Lemă Fiind date n puncte în plan care se unesc între ele prin segmente, astfel încât să nu existe nici un triunghi cu vârfurile în cele n puncte, atunci există cel puțin un punct care este extremitatea a cel mult [n/2] segmente (prin [x] am notat partea întreagă a lui x). Demonstrație Pentru un punct x, fie Ax mulțimea punctelor legate cu x printr-un segment. Presupunem prin absurd că avem card(Ax) ł [n/2] + 1, pentru orice xÎX, unde cu X am notat mulțimea celor n puncte din plan. Fie x Î X și y Î Ax. Avem:
deoarece Dar deci există
Am ajuns însă la o contradicție, deoarece x, y, z sunt vârfurile unui triunghi cu vârfurile în puncte din X. Deci există un punct xÎX astfel încât card(Ax) Ł [n/2]. Astfel demonstrația lemei este încheiată.
Revenind la problema noastră, vom demonstra că atunci când k Ł [n2 / 4] există soluție, iar în cazul când k ł [n2 / 4] + 1, nu există soluție. Demonstrația o vom face prin inducție după n. Pentru n = 1 sau n = 2 rezultatul este imediat, deoarece în primul caz numărul segmentelor este egal cu 0, iar în al doilea caz este egal cu 1. Să presupunem afirmația adevărată pentru n puncte și să o demonstrăm pentru n + 1. Din lema demonstrată anterior rezultă că există un punct x Î X cu card(X) = n + 1, care este extremitatea a cel mult [(n+1)/2] segmente. Dar mulțimea de puncte X - {x} poate fi unită prin cel mult [n2 / 2] segmente astfel încât să nu se formeze nici un triunghi cu vârfurile în aceste puncte, deci numărul total de segmente care unesc punctele din mulțimea X (cu n+1 puncte) este majorat de [(n + 1) / 2] + [n2 / 4]. Vom demonstra în continuare că acest număr este egal cu [(n + 1)2 / 4]. Avem două situații: n par și respectiv n impar. - n = 2h, h Î N. Atunci: [(n + 1) / 2] + [n2 / 4] = h + h2 = [(2h + 1)2 / 4] = [(n + 1)2 / 4], deoarece este evident că [(2h + 1)2 / 4] = [(4h2 + 4h + 1) / 4] = [h(h + 1) + 1/4] = h(h + 1). - n = 2h + 1, h Î N. Atunci: [(n + 1) / 2]+[n2 / 4] = h + 1 + [(4h2 + 4h + 1) / 4] = h + 1 + h(h + 1) = (h + 1)2 = [(n + 1)2 / 4]. Deci am arătat că: [(n + 1) / 2] + [n2 / 4] = [(n + 1)2 / 4].
Acum, în cazul în care k Ł [n2 / 4]), pebtru a obține exact k segmente de dreaptă între cele n puncte astfel încât să nu se formeze nici un triunghi cu vârfurile în aceste puncte, se poate proceda astfel: se grupează cele n puncte în două clase care conțin respectiv [n / 2] și n - [n / 2] puncte și se unesc numai puncte din prima clasă cu puncte din a doua clasă până se obțin k segmente. Programul care rezolvă problema, este următorul:
Listing APP4.PAS Program Aplicatia_4; var n,i,k,h,j:Longint; Begin Write('n='); Readln(n); Write('k='); Readln(k); if k>Trunc(n*n/4) then Write('IMPOSIBIL') else begin h:=0; for i:=1 to Trunc(n/2) do for j:=Trunc(n/2)+1 to n do begin Inc(h); if h<=k then Write('P',i,'P',j,' ') end end End.
Bibliografie
[1] Brânzei D., Brânzei R., Anița S., Anița A., Șiruri recurente în liceu, Ed. GIL, Zalău, 1996
[2] Bușneag D., Maftei I., Teme pentru cercurile și concursurile de matematică ale elevilor, Ed. Scrisul Românesc, Craiova, 1983
[3] Ganga M., Teme și probleme de matematică, Ed. Tehnică, București, 1991;
[4] Sierpinski W., Elementary Theory of Numbers, Warszawa, 1987
Dl. prof. Doru Popescu Anastasiu este cadrul didactic la Colegiul Național "Radu Greceanu" din Slatina. Poate fi contactat prin e-mail la adresa dopopescu@pcnet.pcnet.ro. [cuprins] |