Admitere Informatică Iași 2016 – Subiecte și rezolvări

Admitere Informatică Iași 2016 – Subiecte și rezolvări

În acest articol voi prezenta rezolvările subiectelor date în anul 2016 la admitere la Facultatea de Informatică din Iași. (Aici puteți găsi baremul, însă e foarte sumar.) Dacă sunteți interesați de subiectele din 2017, le găsiți rezolvate aici, iar pe cele din 2018 aici.

Subiectul I. Problema 1.

Un număr natural nn desemnează un an bisect dacă nn este multiplu de 44 dar nu este multiplu de 100100 cu excepția numerelor multiplu de 400400 De exemplu 16001600 20002000 20042004 20162016 și 24002400 sunt ani bisecți, dar 20072007 17001700 18001800 și 22002200 nu sunt ani bisecți. Care dintre expresiile C++ de mai jos testează dacă valoarea variabilei nn desemnează un an bisect?

  1. (n % 100 != 0) && (n % 4 == 0)
  2. (n % 4 == 0) && ((n % 100 != 0) || (n % 400 == 0)
  3. (n % 100 != 0) || (n % 4 == 0)
  4. (n % 4 == 0) && ((n % 100 != 0) && (n % 400 == 0))

Prima expresie nu este corectă pentru că returnează false pentru multiplii lui 400400 din cauza primei condiții. A doua expresie e corectă – este exact definiția unui an bisect tradusă în C++. A treia expresie este greșită pentru că, de exemplu, returnează true pentru numărul 123123 din cauza primei condiții. A patra expresie e o aberație, pentru că un număr nu poate fi divizibil cu 400400 și cu 100100 nu. Deci, varianta corectă este B.

Subiectul I. Problema 2.

Se consideră subprogramul recursiv FF de mai jos, descris în pseudocod. Subprogramul primește ca parametri două numere naturale uu și vv și întoarce un număr natural. Operația % reprezintă restul împărțirii, iar max(a, b) reprezintă maximul dintre aa și bb

subprogram F(u, v)
(u, v - numere naturale)
dacă u = v sau u = 0 sau v = 0 atunci
returnează max(u, v)
altfel dacă u % 2 = 0 atunci
dacă v % 2 = 0 atunci
returnează 2 * F(u / 2, v / 2)
altfel
returnează F(u / 2, v)
altfel
dacă v % 2 = 0 atunci
returnează F(u, v / 2)
altfel
dacă u < v atunci
returnează F(u, (v - u) / 2)
altfel
returnează F((u - v) / 2, v)

a) Care este valoarea returnată de subprogram pentru parametrii u=42u = 42 și v=35v = 35

F(42,35)=F(21,35)=F(21,7)=F(7,7)=7F(42, 35) = F(21, 35) = F(21, 7) = F(7, 7) = 7

b) Dați exemplu de două numere naturale uu vv distincte și nenule astfel încât F(u,v)F(u, v) să returneze 55

Rolul cerinței precedente este să ne dăm seama ce face de fapt funcția dată. În această problemă, se observă ușor că ea calculează cmmdc(u,v)\cmmdc(u, v) într-un mod mai ciudat: Dacă ambele numere sunt pare, le putem înjumătăți, și vom ști că cmmdc\cmmdcul lor este de două ori mai mare decât cmmdc\cmmdcul noilor numere. Dacă un număr este par și celălalt impar, îl putem înjumătăți pe cel par, pentru că factorul 22 nu se găsește și în celălalt, așa că nu va influența cmmdc\cmmdcul lor. Dacă ambele numere sunt impare se aplică algoritmul clasic de determinare a cmmdc\cmmdcului prin scăderi repetate, într-o formă recursivă. Deci, un posibil răspuns pentru această cerință este u=5u = 5 și v=10v = 10 căci cmmdc(u,v)=5\cmmdc(u, v) = 5

c) Dacă u=14u = 14 care este cea mai mare valoare strict mai mică decât 100100 pentru vv astfel încât F(u,v)F(u, v) să returneze 77

Avem nevoie de cel mai mare multiplu de 77 mai mic decât 100100 care nu e divizibil cu 22 (Dacă ar fi divizibil și cu 22 ar fi multiplu de 1414 caz în care cmmdc(u,v)\cmmdc(u, v) ar deveni 1414 Răspunsul e 91=71391 = 7 \cdot 13

d) Scrieți funcția C++ corespunzătoare subprogramului dat.

Un răspuns posibil este:

Subiectul I. Problema 2. Punctul d.
int F(int u, int v) {
if (u == v || !u || !v)
return u > v ? u : v;
if (u % 2 == 0) {
if (v % 2 == 0)
return 2 * F(u / 2, v / 2);
return F(u / 2, v);
}
if (v % 2 == 0)
return F(u, v / 2);
if (u < v)
return F(u, (v - u) / 2);
return F((u - v) / 2, v);
}

Subiectul II. Problema 1.

Care este înălțimea maximă a unui arbore cu rădăcină, având 1111 noduri, știind că fiecare nod intern (care nu este rădăcină sau frunză) are mai multe noduri fiu decât părintele său? (Înălțimea arborelui este numărul de muchii ale celui mai lung drum de la rădăcină la o frunză.)

  1. 22
  2. 44
  3. 1010
  4. Nu există un astfel de arbore

Vom construi arborele astfel: Atribuim un singur fiu rădăcinii, notată cu 11 Acest nod (2\htmlClass{katexified}{(} 2 va trebui să aibă minim doi fii (3\htmlClass{katexified}{(} 3 44 ca să respecte condiția din enunț. Din acești doi fii, pe 44 îl vom lăsa să fie frunză, și extindem arborele doar prin 33 căruia trebuie să-i atribuim trei fii (5\htmlClass{katexified}{(} 5 66 77 Din nou vom încerca să lăsăm cât mai multe frunze, așa că vom continua să adăugăm fii doar la 55 Acesta trebuie să aibă măcar patru fii (8\htmlClass{katexified}{(} 8 99 1010 1111 Adăugându-i pe aceștia, am terminat de construit arborele cerut cu 1111 noduri:

Subiectul II. Problema 1.

Se poate observa că înălțimea lui este 44 Varianta corectă este așadar B.

Subiectul II. Problema 2.

Fie un graf neorientat în care fiecare nod are un număr par și nenul de vecini, astfel încât nu există două noduri având același număr de vecini. Care dintre următoarele variante ar putea reprezenta numărul de muchii ale unui astfel de graf?

  1. 1010
  2. 1515
  3. 1616
  4. Nu există un astfel de graf

Dacă veți încerca să desenați un astfel de graf, veți vedea că trebuie adăugate noduri la infinit pentru a le asigura numărul minim de vecini astfel încât să respecte condițiile problemei. Varianta corectă este D, iar justificarea este că gradele minime ale unui graf cu nn noduri ar trebui să fie 2,4,,2n2, 4, \ldots, 2 \cdot n Însă, gradul maxim al unui nod într-un graf neorientat este n1n - 1 și se obține atunci când „legăm” un nod de toate celelalte noduri. Nu există niciun număr nn natural pentru care 2nn12 \cdot n \le n - 1 așa că putem afirma că nu există un graf de acest tip.

Subiectul II. Problema 3.

Considerăm un șir oarecare format doar din caractere din mulțimea {a,b}\{a, b\} Mulțimea

R={r1:aabaaa,r2:abaaab,r3:abbaba,r4:baaabb,r5:bababa,r6:bbabaa,r7:bbbbab} R = \{r_1: \texttt{aab} \to \texttt{aaa}, r_2: \texttt{aba} \to \texttt{aab}, r_3: \texttt{abb} \to \texttt{aba},\\ r_4: \texttt{baa} \to \texttt{abb}, r_5: \texttt{bab} \to \texttt{aba}, r_6: \texttt{bba} \to \texttt{baa}, r_7: \texttt{bbb} \to \texttt{bab}\}

definește regulile de transformare care pot fi aplicate unui astfel de șir. Fiecare dintre aceste transformări, aplicată unui șir de caractere oarecare, va înlocui prima apariție a subșirului de trei caractere din partea stângă a regulii, cu subșirul din partea dreaptă. Pornind de la șirul inițial, vom aplica în mod repetat oricare dintre transformările din mulțimea RR atât timp cât acest lucru este posibil.

Exemplu: Pentru șirul de caractere abba\texttt{abba} o secvență posibilă de aplicare a regulilor este:

abbar3abaar4aabbr1aaabr1aaaa\texttt{abba} \xrightarrow{r_3} \texttt{abaa} \xrightarrow{r_4} \texttt{aabb} \xrightarrow{r_1} \texttt{aaab} \xrightarrow{r_1} \texttt{aaaa}

a) Demonstrați că, indiferent de șirul considerat inițial și indiferent de ordinea de aplicare a regulilor de transformare, după un număr finit de pași se va obține un șir ce conține pe fiecare poziție doar caracterul aa

În primul rând, se observă că orice transformare conduce la formarea unui șir mai mic lexicografic, de aceeași lungime ca cel precedent. Asta înseamnă că după fiecare transformare aplicată șirului dat, vom fi tot mai aproape de șirul format doar din aa În al doilea rând, știm că nu există niciun șir în care ne putem „bloca”, pentru că fiecare șir de lungime 33 diferit de aaa\texttt{aaa} are asociată o regulă de transformare. Așadar, întotdeauna vom putea ajunge la un șir ce conține pe fiecare poziție caracterul aa

Observație: În enunț ar fi trebuit pusă totuși o restricție legată de lungimea șirului. Aceasta ar trebui să fie minim 33 căci altfel n-am putea aplica nicio transformare asupra lui.

b) Scrieți un program C++ care:

  1. Citește de la tastatură un șir ss format doar din caracterele aa și bb În cazul în care șirul conține și alte caractere, va fi afișat mesajul "Date invalide".
  2. Pornind de la șirul ss aplică toate regulile de transformare din mulțimea RR atât timp cât este posibil și afișează numărul de aplicări ale acestor reguli.
  3. Verifică faptul că șirul rezultat în final este format doar din caractere egale cu aa

Mai jos puteți vedea soluția mea însoțită de comentarii.

Subiectul II. Problema 3. Punctul b.
#include <iostream>
using namespace std;
// Fie 100 lungimea maximă a șirului inițial.
const int SMAX = 101;
int cnt; // numărul de transformări aplicate
char str[SMAX]; // șirul dat
// matrice cu regulile de transformare
char R[8][4] = {"aaa", "aaa", "aab", "aba", "abb", "aba", "baa", "bab"};
int main() {
// Citim și validăm șirul:
cin >> str;
for (int i = 0; str[i]; i++)
if (str[i] != 'a' && str[i] != 'b') {
cout << "Date invalide\n";
return 0;
}
// Aplicăm transformările:
bool ok;
do {
ok = false;
for (int i = 2; str[i]; i++) { // Căutăm o secvență de lungime 3 pe care o putem transforma.
int ind = (str[i] - 'a') + 2 * (str[i - 1] - 'a') + 4 * (str[i - 2] - 'a');
str[i - 2] = R[ind][0]; str[i - 1] = R[ind][1]; str[i] = R[ind][2];
if (ind) { // Dacă secvența nu era "aaa":
cnt++;
ok = true;
}
}
} while (ok);
// Afișăm numărul de transformări efectuate,
// și verificăm dacă toate caracterele șirului curent sunt 'a':
cout << cnt << '\n';
for (int i = 0; str[i]; i++)
if (str[i] != 'a') {
cout << "Sirul final nu este format doar din caractere egale cu a.\n";
return 0;
}
cout << "Sirul final este format doar din caractere egale cu a.\n";
return 0;
}

Pentru a reține regulile convenabil am declarat o matrice RR de tip char cu 88 linii și 44 coloane. Pe fiecare linie am reținut câte o regulă de transformare, pe linia 00 având o regulă „fictivă”, care transformă șirul aaa\texttt{aaa} în aaa\texttt{aaa} Matricea trebuie să aibă minim 44 coloane deoarece pentru inițializarea liniilor am folosit constante de tipul șir de caractere, care au și ele nevoie de loc pentru terminatorul nul. Dacă în schimb am fi inițializat fiecare caracter al matricei în parte, ar fi fost suficiente și 33 linii.

Pentru a înțelege cum am aplicat transformările, trebuie menționat că al iilea șir din RR este chiar numărul ii scris în baza 22 (a\htmlClass{katexified}{(} a însemnând 00 și bb 11 Ca să aplic transformările am utilizat un algoritm asemănător cu Bubble Sort: În do-while parcurg vectorul, iar pentru fiecare ii calculez în indind linia pe care se află regula ce transformă secvența formată din caracterele de pe pozițiile i2i - 2 i1i - 1 și ii din str. Ca să fac asta, convertesc secvența într-un număr scris în baza 1010 După aceea, pur și simplu copiez caracterele din R[ind]R[ind] în str[i2]str[i - 2] str[i1]str[i - 1] și str[i]str[i] Repet procesul cât timp am efectuat măcar o transformare asupra șirului. Verificarea de la finalul programului este inutilă din cauza demonstrației de la punctul a. Dar dacă în enunț zice s-o facem, trebuie făcută!

Subiectul II. Problema 4.

Fie SS și TT două mulțimi de simboluri, ambele având același număr de elemente nn unde nn este un număr natural impar. Un (S,T)(S, T)pătrat este o matrice pătratică de dimensiune n×nn \times n ce îndeplinește următoarele condiții:

  • C1. Fiecare element al matricei este o pereche (s,t)(s, t) unde sSs \in S și tTt \in T
  • C2. Pentru orice două elemente (s,t)(s, t) și (s,t)(s', t') aflate pe poziții diferite în matrice dar pe aceeași linie sau pe aceeași coloană, avem sss \neq s' și ttt \neq t'
  • C3. Pentru orice două elemente (s,t)(s, t) și (s,t)(s', t') aflate pe poziții diferite în matrice, avem sss \neq s' sau ttt \neq t'

Exemplu: Pentru n=3n = 3 S={a,b,c}S = \{a, b, c\} și T={0,1,2}T = \{0, 1, 2\} un (S,T)(S, T)pătrat posibil este:

((a,0)(b,1)(c,2)(c,1)(a,2)(b,0)(b,2)(c,0)(a,1))\begin{pmatrix} (a, 0) & (b, 1) & (c, 2)\\ (c, 1) & (a, 2) & (b, 0)\\ (b, 2) & (c, 0) & (a, 1) \end{pmatrix}

a) Dați un exemplu de (S,T)(S, T)pătrat pentru n=5n = 5 S={a,b,c,d,e}S = \{a, b, c, d, e\} și T={0,1,2,3,4}T = \{0, 1, 2, 3, 4\}

O strategie simplă de a genera o astfel de matrice se poate deduce chiar din exemplul lor: Pe prima linie scriem perechile (a,0)(a, 0) (b,1)(b, 1) (c,2)(c, 2) (d,3)(d, 3) (e,4)(e, 4) Pentru fiecare dintre liniile următoare copiem linia precedentă, dar cu literele permutate circular cu o poziție la dreapta, iar cifrele la stânga.

((a,0)(b,1)(c,2)(d,3)(e,4)(e,1)(a,2)(b,3)(c,4)(d,0)(d,2)(e,3)(a,4)(b,0)(c,1)(c,3)(d,4)(e,0)(a,1)(b,2)(b,4)(c,0)(d,1)(e,2)(a,3))\begin{pmatrix} (a, 0) & (b, 1) & (c, 2) & (d, 3) & (e, 4)\\ (e, 1) & (a, 2) & (b, 3) & (c, 4) & (d, 0)\\ (d, 2) & (e, 3) & (a, 4) & (b, 0) & (c, 1)\\ (c, 3) & (d, 4) & (e, 0) & (a, 1) & (b, 2)\\ (b, 4) & (c, 0) & (d, 1) & (e, 2) & (a, 3) \end{pmatrix}

b) Scrieți o funcție C++ care primește ca argumente numărul natural impar nn și două tablouri de caractere, reprezentând mulțimile SS și TT și construiesc un (S,T)(S, T)pătrat.

Cum în enunț matricea pe care trebuie să o construim nu este inclusă în lista de parametri, iar funcțiile nu pot returna tablouri, am declarat global o matrice mat. Aceasta conține elemente de tipul Pair, care este un struct definit de mine cu două câmpuri: x și y. În rest nu prea am ce comenta, funcția f construiește matricea exact după procedeul descris la cerința anterioară.

Subiectul II. Problema 4. Punctul b.
// (NMAX - 1) = valoarea maximă a lui n
// Indexăm matricea și tablourile S și T de la 1.
const int NMAX = 101;
struct Pair {
char x, y;
} mat[NMAX][NMAX]; // matricea construită de f()
void f(int n, char S[], char T[]) {
for (int j = 1; j <= n; j++) {
mat[1][j].x = S[j];
mat[1][j].y = T[j];
}
for (int i = 2; i <= n; i++) {
mat[i][1].x = mat[i - 1][n].x;
for (int j = 2; j <= n; j++)
mat[i][j].x = mat[i - 1][j - 1].x;
mat[i][n].y = mat[i - 1][1].y;
for (int j = 1; j < n; j++)
mat[i][j].y = mat[i - 1][j + 1].y;
}
}

c) Argumentați faptul că pătratul construit de funcția de la punctul b îndeplinește condițiile C1, C2 și C3.

Condiția C1 este îndeplinită trivial, pentru că pe prima linie a matricei punem în câmpurile xx elemente din SS în câmpurile yy elemente din TT iar restul liniilor folosesc elemente de pe liniile precedente. Condiția C2 se verifică și ea ușor: Elementele de pe orice linie sunt o permutare a vectorilor SS respectiv TT elementele fiind clar distincte. Fiind vorba de permutări circulare, și coloanele vor fi de fapt niște permutări circulare, deci și ele respectă această condiție.

Condiția C3 se demonstrează mai greu însă. Pentru ca două elemente de pe poziții diferite să fie egale, trebuie ca în primul rând câmpurile lor xx să fie la fel. Observăm că fiecare element din SS apare pe o diagonală paralelă cu diagonala principală. (De fapt pe două, dacă nu este vorba chiar de cea principală, însă ne putem imagina că acestea formează una singură.) Acum trebuie să căutăm două elemente de pe această diagonală cu yyurile egale, însă nu vom găsi! Asta pentru că pe fiecare diagonală de genul ăsta apare chiar o permutare a lui TT elementele crescând din 22 în 22

Să luăm un exemplu concret – matricea de la punctul a:

((a,0)(b,1)(c,2)(d,3)(e,4)(e,1)(a,2)(b,3)(c,4)(d,0)(d,2)(e,3)(a,4)(b,0)(c,1)(c,3)(d,4)(e,0)(a,1)(b,2)(b,4)(c,0)(d,1)(e,2)(a,3))\begin{pmatrix} (a, 0) & (b, 1) & \mathbf{(c, 2)} & (d, 3) & (e, 4)\\ (e, 1) & (a, 2) & (b, 3) & \mathbf{(c, 4)} & (d, 0)\\ (d, 2) & (e, 3) & (a, 4) & (b, 0) & \mathbf{(c, 1)}\\ \mathbf{(c, 3)} & (d, 4) & (e, 0) & (a, 1) & (b, 2)\\ (b, 4) & \mathbf{(c, 0)} & (d, 1) & (e, 2) & (a, 3) \end{pmatrix}

Am îngroșat diagonala pe care se află litera cc Cifrele de pe această diagonală apar de sus în jos în ordinea 2,4,1,3,02, 4, 1, 3, 0 După 44 urmează 11 și după 33 urmează 00 pentru că parcurgerea lui TT se ia de la capăt când se ajunge la final. Cum nnul este impar și cifrele cresc din 22 în 22 ele nu se vor repeta. Dacă în schimb nnul ar fi fost par, să zicem 44 cifrele ar fi fost 2,0,2,02, 0, 2, 0 așa că (cel puțin) strategia noastră de completare a matricei n-ar mai fi funcționat.

Subiectul III. Problema 1.

Se consideră toate șirurile de lungime 1010 formate din 00 și 11 Câte dintre acestea au proprietatea că suma oricăror 55 elemente de pe poziții consecutiive este 33

  1. 1010
  2. 100100
  3. 120120
  4. 10241024

Ideea de bază este că dacă avem fixați primii 55 termeni ai șirului, celelalte elemente sunt determnate în mod unic: Analizăm pe rând fiecare secvență de lungime 55 Observăm că pentru a trece de la o secvență la următoarea, trebuie să eliminăm primul element din stânga și să inserăm unul nou la dreapta, astfel încât suma elementelor noii secvențe să fie 33 Dacă elementul eliminat este 11 suma elementelor rămase devine 22 așa că trebuie să adăugăm neapărat 11 pentru a reveni la suma 33 Dacă elementul eliminat este 00 suma rămâne 33 așa că trebuie să adăugăm tot 00 pentru a nu o modfica.

Acum că am demonstrat asta, putem spune că numărul de șiruri cu proprietatea dată este egal cu numărul de șiruri binare de lungime 55 cu suma elementelor 33 Adică numărul de șiruri de lungime 55 formate din 33 elemente de 11 și 22 elemente de 00 Acesta este egal cu C53=10C_5^3 = 10 Prin urmare, varianta corectă este A.

Subiectul III. Problema 2.

John McCarthy, unul dintre fondatorii domeniului inteligență artificială, a propus funcția F91F91 definită mai jos și numită funcția 91 a lui McCarthy. Ce valoare va returna apelul F91(91)F91(91)

int F91(int x) {
if (x > 100)
return x - 10;
else
return F91(F91(x + 11));
}

Trebuie doar să urmărim lanțul de apeluri recursive. Pentru a nu ne încurca, am schimbat numele funcției în FF simplu…

F( 91) = F(F( 91 + 11 = 102)) =
F( 92) = F(F( 92 + 11 = 103)) =
F( 93) = F(F( 93 + 11 = 104)) =
F( 94) = F(F( 94 + 11 = 105)) =
F( 95) = F(F( 95 + 11 = 106)) =
F( 96) = F(F( 96 + 11 = 107)) =
F( 97) = F(F( 97 + 11 = 108)) =
F( 98) = F(F( 98 + 11 = 109)) =
F( 99) = F(F( 99 + 11 = 110)) =
F(100) = F(F(100 + 11 = 111)) =
F(111) = 91

Subiectul III. Problema 3.

Fie AA o matrice de numere naturale cu N2N \ge 2 linii și M2M \ge 2 coloane. O secvență (i1,j1),(i2,j2),,(ik,jk)(i_1, j_1), (i_2, j_2), \ldots, (i_k, j_k) de pe poziții din AA se numește progresivă dacă șirurile

  • i1,i2,,iki_1, i_2, \ldots, i_k
  • j1,j2,,jkj_1, j_2, \ldots, j_k
  • A[i1][j1],A[i2][j2],,A[ik][jk]A[i_1][j_1], A[i_2][j_2], \ldots, A[i_k][j_k]

sunt progresii aritmetice cu rații nenule. De exemplu, în matricea

(223530372534268442341103823142049113520322413)\begin{pmatrix} 22 & \mathbf{35} & 30 & 37 & 25 & 34\\ 26 & 8 & 44 & \mathbf{23} & 41 & 10\\ 38 & 23 & 14 & 20 & 49 & \mathbf{11}\\ 35 & 20 & 3 & 2 & 24 & 13 \end{pmatrix}

este evidențiată secvența progresivă (1,2),(2,4),(3,6)(1, 2), (2, 4), (3, 6) Indicii liniilor (1,2,3)(1, 2, 3) sunt în progresie aritmetică de rație nenulă, indicii coloanelor (2,4,6)(2, 4, 6) sunt în progresie aritmetică de rație nenulă, iar valorile (35,23,11)(35, 23, 11) sunt și ele în progresie aritmetică de rație nenulă.

a) Pentru matricea de mai jos, scrieți care este cea mai lungă secvență progresivă. Dacă sunt mai multe astfel de secvențe, alegeți oricare dintre ele.

(11191116111371111211151191111131131)\begin{pmatrix} 1 & 1 & 1 & 9 & 1\\ 1 & 1 & 6 & 1 & 1\\ 1 & 3 & 7 & 1 & 1\\ 1 & 1 & 2 & 1 & 1\\ 1 & 5 & 1 & 1 & 9\\ 1 & 1 & 1 & 1 & 1\\ 3 & 1 & 1 & 3 & 1 \end{pmatrix}

O secvență progresivă de lungime maximă din matricea dată este

(1,4),(3,3),(5,2),(7,1)(1, 4), (3, 3), (5, 2), (7, 1)

Cealaltă variantă se obține scriind această secvență în ordine inversă. Evident că dacă o secvență este progresivă, atunci și „inversa” ei este progresivă, pentru că doar rațiile s-ar schimba (s-ar înmulți cu 1-1

b) Scrieți o funcție C++ care primește ca parametri dimensiunile NN și MM ale matricei, matricea AA și primele două poziții (i1,j1)(i_1, j_1) (i2,j2)(i_2, j_2) dintr-o secvență progresivă din AA Funcția va returna lungimea secvenței progresive din AA ce începe cu (i1,j1)(i_1, j_1) (i2,j2)(i_2, j_2) și care are un număr maxim de elemente.

Presupunem că pozițiile date reprezintă un început valid de secvență progresivă, și anume că rațiile formate sunt nenule. Mai întâi calculez în iR, jR și xR rațiile liniilor, coloanelor și ale elementelor. Apoi, folosind un for destul de complex (dar logic), incrementez lungimea secvenței cât timp elementele selectate continuă să se afle în progresie aritmetică.

Subiectul III. Problema 3. Punctul b.
// (NMAX - 1) = valoarea maximă a lui N
// (MMAX - 1) = valoarea maximă a lui M
int maxLen(int N, int M, int A[NMAX][MMAX], int i1, int j1, int i2, int j2) {
int iR = i2 - i1;
int jR = j2 - j1;
int xR = A[i2][j2] - A[i1][j1];
int len = 2;
for (int i = i2 + iR, j = j2 + jR;
1 <= i && i <= N && 1 <= j && j <= M && A[i][j] == A[i - iR][j - jR] + xR;
i += iR, j += jR)
len++;
return len;
}

c) Scrieți o funcție C++ care primește ca parametri dimensiunile NN și MM ale matricei și matricea AA Funcția va returna lungimea secvenței progresive din AA care are un număr maxim de elemente. În rezolvare, puteți apela funcția de la punctul b.

Din moment ce în enunț se specifică faptul că putem folosi funcția precedentă, este destul de clar că trebuie pur și simplu să alegem toate începuturile posibile de secvență progresivă, să calculăm lungimea fiecăreia, iar la final să returnăm maximul obținut. Trebuie să avem grijă ca fiecare pereche de poziții de start să fie validă, adică să nu formeze vreo rație zero. Este posibil să nu existe nicio pereche validă de poziți de start, caz în care trebuie returnat 1. Am tratat acest caz inițializând variabila sol cu 1.

Subiectul III. Problema 3. Punctul c.
int maxLen(int N, int M, int A[NMAX][MMAX]) {
int sol = 1;
for (int i1 = 1; i1 <= N; i1++)
for (int j1 = 1; j1 <= M; j1++)
for (int i2 = 1; i2 <= N; i2++)
if (int i2 != i1)
for (int j2 = 1; j2 <= M; j2++)
if (int j2 != j1 && A[i1][j1] != A[i2][j2]) {
int len = maxLen(N, M, A, i1, j1, i2, j2);
if (len > sol)
sol = len;
}
return sol;
}

Se vede clar că algoritmul are o complexitate de ordinul O((NM)2)O((NM)^2) Am putea face o mică optimizare, și anume să folosim observația de la punctul a pentru a nu parcurge de două ori aceeași secvență din direcții diferite. Dar complexitatea rămâne aceeași, așa că nu are sens să ne complicăm.


Astea au fost subiectele de la admitere din 2016. Mie mi s-au părut ceva mai grele decât cele din 2017 și 2018, în special datorită cerinței II.4.2 și a argumentării răspunsului de la problema II.2. (Chiar dacă subiectul spune doar să scrieți litera corespunzătoare răspunsului corect, se punctează și justificarea.) Dacă aveți vreo întrebare legată de problemele din acest articol, nu ezitați să lăsați un comentariu mai jos :smile:

Mulțumesc că ai citit acest articol.
Dacă vrei să susții blogul, poți cumpăra un abonament de 2$.

patreon

Lasă un comentariu!

0 comentarii