Studiu - dev, arhiva blogului, structuri de date și algoritmi

structuri de date și algoritmi. Teorie. problemă de programare clasică

Această secțiune descrie algoritmii și tehnicile comune specifice pentru a solicita un non-triviale programe de prelucrare a informațiilor. În aceste algoritmi vor fi acordat o atenție nu numai la corectitudinea algoritmului, dar, de asemenea, pe optimizarea utilizării resurselor de calcul. Pentru luarea în considerare a acestei clase de probleme algoritmului este de obicei scris pe o pseudo - limbaj, care ocupă o poziție intermediară între limbă și programare limbile noastre obișnuite și are anumite reguli și cerințe stricte ca Proiectat în primul rând pentru om, nu un calculator. Acest lucru ne va permite să scape de algoritm detalii inutile într-un stadiu incipient de dezvoltare și dreptul de a-și exprima ideea lui de bază.

Conceptele de bază utilizate în rezolvarea problemelor enumerate mai jos - este nejustificată, recurențe, sortarea, aruncând înapoi (backtracking). Aceste concepte trebuie să fie competenți în fiecare programator. Multe instituții cele mai multe dintre locurile de munca acestor sarcini constituie planul de olimpiada. În plus, ar trebui să păstreze întotdeauna în vedere faptul că, deși problemele de căutare, cu condiția o implementare competentă poate găsi aproape întotdeauna o soluție nu este evident algoritmic, ca acestea se bazează pe metode euristice sunt folosite, dar trebuie să le utilizați cu precauție. Din moment ce metode euristice sunt mai scumpe. decât algoritmică și, prin urmare, nu trebuie utilizat neglijent în orice situație adecvată.

Recursivitatea și probleme de căutare

Recursivitatea cel mai frecvent utilizate pentru rezolvarea problemelor de căutare. Probleme similare sunt umplute cu multe cărți populare, acestea sunt o parte integrantă a aproape fiecare Olimpiada de Informatica din liceu și școală profesională să nu mai vorbim de universități. Considerăm utilizarea sistemului de recursivitate pentru rezolvarea acestei clase de probleme atât cu revenirea problemei (backtracking). Să analizăm în mod specific backtracking schema de aplicare pentru rezolvarea problemei cu cavaler de șah.

Exemplu: Având în vedere o dimensiune tablă de șah N * N. Fiecare celulă a plăcii este numerotat în ordine de la 1 la N ^ 2. Calul se mișcă în normele obișnuite de șah. Trebuie să găsim o cale prin toate celulele în care vom vizita în toate domeniile și doar o singură dată. Dimensiunile plăcii sunt calul și poziția inițială (coordonatele sale de-a lungul ambelor axe) datele inițiale. Soluția ar trebui să fie doar recursiv.

Exemplul de imagine în centrul de bord este foarte cal. Cifrele arată posibile în jurul celulelor pentru prima mutare. Pentru a avea o metodă standardizată de calculare a tuturor celulelor, care se pot deplasa de la poziția curentă, se recomandă să se utilizeze un tablou auxiliar de marimea 2 * 8. Aici, primul rând pentru coloana specificată K este incrementată cu axa OY, respectiv valoarea string a doua este incrementată cu axa OX. Un exemplu de astfel de matrice este dată mai jos (**):

Înainte de a începe funcția noastră recursivă, noi o numim cal, funcția principală este de a efectua lucrări pregătitoare - pentru a umple matricea sursă cu zerouri - se presupune că valoarea fiecărei celule este diferit de zero - este numărul de progres secvențial, care au condus la această poziție, la zero, presupunem, respectiv, un semn că, în această celulă, încă nu am ajuns. Ca parametrii în apelul funcției care urmează să fie transmis de cai coordonatele celulei curente (I, J), precum și numărul de accident vascular cerebral S.

Fiecare recursive profunzime apel S încearcă să plaseze calul în toate celulele posibile, care pot fi accesate direct de curent (I, J) celule pentru această placă la coordonate curent (I, J) ofset coeficienți se adaugă la rândul lor (**). Desigur, că fiecare dintre coordonatele rezultate trebuie verificate pe această temă dacă ne-am mutat dincolo de tabla de șah. Deci, obținerea unui nou coordonate (I1, J1) vom verifica pentru a vedea dacă putem face pentru a muta acea dacă celula este gol (adică zero). În cazul în care o astfel de mișcare este posibil, vom face acest lucru prin punerea în cușcă valorii matrice noastre A [I1, J1] = S. Prin această mișcare, vom simplifica problema originală, acum avem nevoie pentru a obține în jurul valorii are N ^ 2 - S celule de bord. Ar trebui să menționăm, de asemenea, existența așa-numitele „fundături“ - este astfel de stări în care nu au fost încă finalizate toate celulele, dar starea actuală nu există nici un loc pentru a merge. Ceea ce am ajuns la un impas înseamnă că undeva în etapele anterioare ale modului, am făcut o greșeală și a ales calea greșită, de aceea, trebuie să ne întoarcem și se repetă cu timpul eșecului sunt deja selectați o altă celulă. Și acum atenția: în acest fel și intră orice algoritm de căutare recursiv: la un anumit stadiu recursivitatii cuibărit (etapa de coborâre), atunci când vom lua o decizie cu privire la care dintre mai multe moduri posibile de a alege, salvate într-o stivă de funcții de memorie locale, toate variabilele și parametrii, fiecare copii ale următoarelor funcții vor lucra cu copii lor de variabile. Așa că atunci când ne ridicăm etapă trage înapoi la starea sa anterioară este păstrată datorită valorilor variabilelor știu deja exact ce cale am trecut și care a rămas. Această lucrare este o căutare recursiv este similar cu modul în care turiștii sunt în căutarea pentru căutarea în pădure drumul spre casă. Sau ceva de genul o mașină de joc de șah cu un om într-un anumit joc enumără (căutări, utilizează euristica) pentru a decide cum să meargă.

Codul Exemplu sursă al algoritmului este dat mai jos:

Înlocuirea recursivitate stivă

În cazul în care trebuie să pună în aplicare o căutare, dar este necesar pentru a reduce aeriene recursivitatii, o puteți înlocui cu o stivă. Ceea ce urmează este un exemplu de cod care a rezolvat sarcina de a găsi cele mai mari pete pe piele de leopard. Matricea dreptunghiulară de dimensiune N * M umplut cu zerouri și cele este necesară pentru a găsi cea mai mare suprafață de unități continue. Următoarele este o soluție cu utilizarea recurenței și printr-o stivă. Înlocuirea este posibilă datorită faptului că, punct de vedere tehnic, recurență este pus în aplicare prin stocarea opțiunile posibile pentru strategiile de dezvoltare pentru a aborda și de a reveni la ele în disciplina LIFO. De notat special, este faptul că înlocuirea recursivitatii utilizând stiva ar trebui să se facă atunci când recursivitate este un nivel foarte semnificativ, în această situație nu putem bătături suficient de stivă de memorie de calculator, și pentru că stiva putem plasa în grămadă, atunci limita dimensiunea sa este mai puțin sensibilă.

Pentru soluții non-recursive nevoie pentru a conecta o clasă stivă de la biblioteca STL. Următorul este un exemplu de soluții funcționale non-recursive. Pentru a verifica funcționarea sa ar trebui să fie înlocuite în cele de mai sus listare funcția de apel „recursive_calc“ pe „stack_calc“.

Sarcina: toate sarcinile, care sunt enumerate mai jos și sunt recursiv, vor trebui, de asemenea, să fie puse în aplicare cu ajutorul stivei. Puteți încerca să estimeze timpul petrecut în ambele abordări.

Sarcini: Ceea ce urmează este o listă de sarcini care implică decizia de a utiliza Recursivitate și backtracking metode pentru a căuta soluții.

1) opt regine puzzle: pe bord trebuie să fie plasat opt ​​regine, astfel încât nici unul dintre ei a fost sub atac atât.

2) În cazul în care călătoresc cu trenul, fata din tren a înlocuit numele fiecărei litere în locul său în alfabetul românesc și a primit de intrare de cele și doi cate doi „211221-21221“. Determina cum și în cazul în care trenul se întâmplă?

3) Datele N pietre de domino în conformitate cu normele stabilite într-un lanț linear, începând cu semințe, selectate aleatoriu, în ambele capete, atâta timp cât este posibil. Construi un algoritm pentru a determina o opțiune de a pune unele semințe de date, în care momentul în care lanțul nu poate fi continuat, „pe mâinile lor“ va fi numărul maxim de puncte.

4) Expresia scrisă ((((1? 2) 3) 4) 5) 6 în loc de fiecare caracter. se introduce una dintre cele patru operații aritmetice +, -, *, /, astfel încât rezultatul calculului este egal cu 35 (prin împărțirea părții fracționare este eliminată în particular). Găsiți toate soluțiile.

5) să introducă un șir de nu mai mult de 6 cifre și unele R. întreg puncționare operatori matematici ( „+“, „-“, „*“, „/“, nu este un minus unar, adică, nu poate reprezenta negativitate număr, diviziune este diviziune întreagă, adică, 11/3 = 3) și deschiderea și paranteza de închidere, astfel încât să rezulte un calcul al expresiei care rezultă numărul de R. eroarea între paranteze inutile nu sunt.
6) Crearea unui program care imprimă toate diferit reprezentarea numărului N în forma tuturor produselor posibile (sume) numere întregi K (N, K-intrat, 1