Documente Academic
Documente Profesional
Documente Cultură
Justfindthisinfoproject
Justfindthisinfoproject
1. Enunţul problemei.......................................................................................2
2. Metoda Backtracking..................................................................................3
2.1. Descrierea generală a metodei................................................................3
2.2. Mecanismul
metodei.................................................................................4
2.3. Algoritmul metodei...................................................................................5
2.3.1. Descrierea algoritmului iterativ...........................................................5
2.3.2. Descrierea algoritmului recursiv..........................................................7
3. Subprograme.............................................................................................10
3.1. Variabile locale şi globale.....................................................................10
3.2. Parametri...............................................................................................10
3.3.
Proceduri................................................................................................11
3.4. Funcţii....................................................................................................12
4. Tipul
mulţime.............................................................................................13
4.1. Definirea şi declararea tipului mulţime.................................................13
4.2. Operaţii permise pe tipul de date set.....................................................14
4.3. Constante cu tip
mulţime........................................................................15
5. Rezolvarea
problemei................................................................................17
5.1. Metoda
1.................................................................................................18
5.2. Metoda
2.................................................................................................23
1
6.2. Metoda
2.................................................................................................31
1. Enunţul problemei
Problema scaunelor
2
2. Metoda Backtracking
- metoda Greedy;
- metoda Divide et impera;
- metoda Branch and Bound;
- metoda Backtracking;
3
Generarea tuturor tablourilor X cu elementele produsului cartezian M1хM2х…хMn
- numit spaţiul soluţiilor posibile – conduce la un timp de execuţie foarte mare.
Metoda Backtracking are la bază o strategie prin care se generează doar soluţiile
care îndeplinesc condiţiile specifice problemei, denumite condiţii interne.
Soluţiile posibile care respectă condiţiile interne se numesc soluţii rezultat.
Daca un element xj primeşte o valoare din mulţimea Mj care este admisă în
soluţia rezultat, această valoare se numeşte valoare validă. Condiţiile de validare sunt
deduse din condiţiile interne.
Problemele care se rezolvă cu această metodă pot avea anumite particularităţi :
numarul n de elemente care pot participa la construirea unei soluţii nu este o
valoare constantă ;
se poate obţine si o singură soluţie, denumită solutie optimă ;
elementele x1, x2, …, xn ale unei soluţii pot fi şi ele tablouri
mulţimile M1, M2, …, Mn pot avea aceleaşi elemente.
Concret :
• se alege primul element x1, ce aparţine lui A1;
• presupunând generate elementele x1, x2,…, xk, aparţinând mulţimilor A1, A2,.. , A , K
se alege (dacă există) xk+1, primul element disponibil din mulţimea Ak+1, apărând
două posibilitaţi:
1) nu s-a găsit un astfel de element, caz în care se reia căutarea considerând generate
elementele x1, x2, …, xk, iar aceasta se reia de la următorul element al multimii Ak, rămas
netestat;
2) a fost găsit, caz în care se testează dacă acesta indeplineşte anumite condiţii de
continuare, apărând astfel două posibilităţi:
2.1) le indeplineşte, caz în care se testează dacă s-a ajuns la soluţie şi
apar, din nou, două posibilităţi:
2.1.1) s-a ajuns la soluţie, se tipăreşte soluţia şi se reia algoritmul
considerând generate elementele x1, x2, …, xk (se caută, în continuare, un
alt element al mulţimii Ak,, rămas, netestat);
2.1.2) nu s-a ajuns la soluţie, caz în care se reia algoritmul considerând
generate elementele x1, x2,…, xk1 şi se caută un prim element xk+2 є Ak+2.
2.2) nu le indeplineşte, caz în care se reia algoritmul considerând
4
generate elementele x1, x2 ,…, xk, iar elementul xk+1 se caută între
elementele mulţimii Ak+1 rămase netestate
Toţi algoritmii sunt reprezentaţi print-o succesiune logică şi finită de paşi descrişi
prin structuri specifice: structuri secvenţiale, structuri decizionale si structuri repetitive.
Un algoritm care conţine structuri repetitive poate fi reprezentat : iterativ sau
recursiv.
Prezentarea iterativă a unui algoritm repetitiv implică reluarea parcurgerii
secvenţei de operaţii până când este indeplinită condiţia de oprire. În limbajele de
programare cunoscute, structurile repetitive sunt implementate iterativ cu ajutorul
intrucţiunilor corepunzătoare.
Un algoritm recursiv conţine un bloc procedual care se autoapelează, altfel spus se
apelează prin el însuşi din interiorul său. Din afara blocului procedual se face un prim
apel al acestuia, după care blocul se autoapelează de un anumit număr de ori ; la fiecare
nouă autoapelare se execută secvenţa de intrucţiuni din codul său, eventual cu alte date,
realizându-se un aşa-numit, « lanţ de apeluri recursive ».
Tipuri de recursivitate :
a) Recursivitate directă
Dacă un subprogram se autoapelează până la întâlnirea condiţiei de oprire se
spune că recurivitatea este directă. În acest caz se execută urmatorii paşi :
Pasul 1. Apelul subprogramului recursiv.
Pasul 2. Autoapelul subprogramului până la îndeplinirea condiţiei de oprire
Pasul 3. Revenirea la modulul apelant.
b) Recurivitate indirectă
Dacă există două sau mai multe subprograme care se apelează reciproc până când
se intâlneşte condiţia de oorpire în cel puţin unul dintre ele, recursivitatea este indirectă
sau încrucişată. În acest caz se execută următorii paşi :
Pasul 1. Apelul subprogramului.
Pasul 2. Apeluri încrucişate până la întâlnirea condiţiei de oprire.
Pasul 3. Revenirea la modulul apelant.
5
Stiva este acea formă de organizare a datelor (structură de date) cu proprietatea
că operaţiile de introducere şi scoatere a datelor se fac în vârful ei.
Pentru a înţelege modul de lucru cu stiva, ne imaginăm un număr n de farfurii
identice, aşezate una peste alta (o "stivă" de farfurii). Adăugarea sau scoaterea unei
farfurii se face, cu uşurinţă, numai în vârful stivei. Dacă toate cele n farfurii sunt aşezate
una peste alta, spunem că stiva este plină. După ce am scos toate farfuriile din stivă,
spunem că aceasta este vidă. Oricât ar părea de simplu principiul stivei, el are
consecinţe uriaşe în programare.
Stivele se pot simula utilizând vectori.
Fie ST(i) un vector. ST(1), ST(2), …, ST(n) pot reţine numai litere sau numai cifre.
O variabilă K indică în permanenţă vârful stivei.
Exemplificăm, în continuare, modul de lucru cu stiva:
6
…
Xk
…
…
X2
X1
ST
7
• recursivitatea este acel mecanism prin care un subprogram (functţe, procedură) se
autoapelează.
Atunci când scriem un algoritm recursiv, este suficient să gândim ce se întamplă la un anumit
nivel, pentru că la orice nivel se întamplă exact acelaşi lucru.
Totusi, exemplul prezentat are un neajuns, prezentând un şir infinit de ‘televizoare’.
Un algoritm recursiv corect trebuie să se termine, contrar programul se va termina cu eroare
şi nu vom primi rezultatul aşteptat. Condiţia de terminare va fi pusă de către programator.
Un rezultat matematic de excepţie afirmă că pentru orice algoritm iterativ exista unul
recursiv echivalent (rezolvă aceeaşi problemă) şi invers, pentru orice algoritm recursiv exist a unul
iterativ echivalent.
Cu toate acestea, fiind dată o problemă trebuie bine să ne gândim dacă pentru ea se va
elabora un algoritm recursiv sau unul iterativ. Sunt cazuri când elaborarea unui algoritm
recursiv duce la un timp de calcul foarte mare (de ordinul anilor sau chiar secolelor) iar
dacă elaborăm un algoritm iterativ timpul necesar de calcul este cu mult mai mic. Pe de
altă parte, scriind un algoritm recursiv se obţine un text sursă extrem de scurt şi de cele mai multe
ori clar.
Mecanismul prezentat mai sus poate fi generalizat cu usurintă pentru obţinerea recursivităţii.
Atunci când o procedură sau funcţie se autoapelează se depun în stivă:
• valorile parametrilor transmişi prin valoare;
• adresele parametrilor transmişi prin referinţă;
• valorile tuturor variabilelor locale (declarate la nivelul procedurii sau funcţiei).
8
Revenim la autoapel. Să presupunem că procedura (funcţia) s-a autoapelat.
Instrucţiunile rămân nemodificate. Procedura (funcţia) va lucra asupra datelor
transmise pe stivă. În cazul unui nou autoapel, se creează un alt nivel pentru stivă, în
care se depun noile valori. Odată indeplinită condiţia de terminare, urmează să se
revină din autoapelări. Procedura care s-a autoapelat se reia de la instrucţiunea care
urmează autoapelului. Ea va lucra cu variabilele (valorile) reţinute pe stiva in momentul
autoapelului, la care se adaugă valorile returnate (o funcţie returneaza o valoare, o
variabila transmisă prin referinta a fost, eventual, modificată).
Se depune pe prima poziţie din tabloul soluţie (k=1) o valoare iniţială (X[1]←1).
Variabila k pastrează poziţia curentă din taboul X în care se va depune un nou
element.
Se caută în mulţimea Mk de valori prima valoare (prin incrementarea valorii
curente a elementului xk, X[k]=X[k]+1) care respectă condiţiile interne. Această valoare
xk se compară cu elementele depuse în tablou pentru a se verifica condiţiile de validare
(valid(xk)).
Dacă valoarea gasită pentru xk poate participa la generarea soluţiei, atunci se
verifică dacă s-au completat cu valori toate elementele din soluţie; dacă s-a generat o
soluţie, aceasta este tiparită; astfel, se trece la următorul candidat la generarea soluţiei
prin autoapelul algoritmului. Prin autoapel se trece la un nou element din tabloul soluţie
X.
Dacă în mulţimea Mk nu mai există valori pe care să le poată prelua x k se caută o
nouo valoare pentru elementul xk-1 (k←k-1). Această trecere la elementul xk-1 se face pe
baza mecanismului recursivităţii la revenirea dintr-o instanţă a subprogramului recursiv
(prin extragerea din vârful stivei a fiecărei valori depuse, se coboară în stivă).
Generarea soluţiilor are loc cât timp, pentru primul element al tabloului soluţie,
mai există valori în mulţimea M1. Dacă nu mai există astfel de valori, poziţia curentă k,
în tablou, devine zero şi algoritmul de generare se opreşte.
9
3. Subprograme
În cadrul unui subprogram pot fi declarate variabile, sintaxa fiind aceeaşi cu cea
folosită în declararea variabilelor la începutul unui program.
Pentru un subprogram, variabilele proprii (definite în interiorul său) se numesc
variabile locale, iar cele definite în programul principal se numesc variabile globale.
Pentru ca o variabilă să fie bine definită, trebuie specificate:
• Numele;
• Tipul de date pe care le va pastră
10
• Zona de memorie – tipul de memorie internă în care variabila este
memorată. Variabilele oricărui program pot fi memorate în : segmentul de
date, segmentul de stivă, heap sau într-un registru dedicat al
microprocesorului.
• Durata de viaţă – intervalul de timp în care variabila dispune de locaţia de
memorie atribuită ei de compilator
• Domeniul de vizibilitate – segmentul de program în care variabila poate fi
uitilizată.
Variabilele globale sunt văzute din momentul declararii până la sfârşitul
programului, pe când cele locale sunt văzute doar în subprgramul unde au fost
declarate.
3.2. Parametri
La scrierea unui subprogram parametrii sunt precizaţi sub forma unei liste de
parametri formali, care se comportă asemenea unor variabile locale. Ei sunt valabili
numai în interiorul subprogramului, după încheierea acestuia pierzându-şi valabilitatea.
Acestia sut precedaţi de cuvântul VAR.
Parametrii formali se deosebesc de variabilele locale prin aceea că în momentul
apelului sunt iniţializaţi cu valori din programul apelant. Aceste valori se numesc
parametri efectivi. Parametrii formali sunt entităţi simbolice asupra cărora se fac
referiri în instrucţiunea compusă ce constituie corpul subprogramului.
11
3. 3. Proceduri
Procedura este un subprogram care primeşte oricâte valori ca date de intrare şi
poate returna ca rezultat o valoare, mai multe valori sau nici una (poate efectua o
prelucrare care să nu aibă ca efect obţinerea unei valori).
Declarare :
Procedure nume([var] par_formal1, …, par_formaln :tip1 ; … ; [var] par_formal1, …,
par_formalm :tipk) ;
Apelare :
Nume(par_actual1 ; par_actual2 ; ... ; par_actualm) ;
3. 4. Funcţii
Declarare :
Function nume (par_formal1, …, par_formaln :tip1 ; …; par_formal1, …,
par_formalm :tipk) :tip ;
Apelare :
X := nume(par_actual1 ; par_actual2 ;... ; par_actualm) ;
Sau :
Write(nume(par_actual1 ; par_actual2 ;... ; par_actualm) ) ;
12
- în blocul de instrucţiuni executabile al funcţiei trebuie să existe cel putin o
intrucţiune de atribuire având ca membru stâng numele funcţiei.
Funcţia se apelează prin nume şi lista de prametri actuali în interiorul unei
expresii.
4. Tipul mulţime
Conceptul de mulţime este implementat de limbajul Turbo Pascal 7.0. prin tipul de
date set.
Mulţimea de valori a tipului de date set este formată din submulţimi ale unui tip
ordinal.
Diagrama pentru declararea lui este următoarea:
Exemplu:
type litere=set of char;
numere=set of byte;
cif_imp=(unu,trei,cinci, şapte,noua)
var
a:set of cif_imp;
b: litere;
13
Se observă că declararea lui poate fi făcută şi ca tip anonim al unei variabile.
Tipul ordinal se mai numeşte şi tip de bază.. El nu poate cuprinde mai mult de 256 de
valori.
Constructor mulţime
[ ]
membru
Membru expresie
. expresie
.
Exemplu:
- [] reprezintă mulţimea vidă, aceptată ca element al oricărui tip set;
- [2.. 7] este mulţimea ce conţine elementele 2, 3, 4, 5 , 6, 7;
- [2, 4, 2*4 . . (20 div 2)] este mulţimea care conţine elementele 2, 4,
8, 9, 10,
- [’a’, ’e’, ’i’, ’A’..’C’] este mulţimea ce conţine elementele ' a', ’e’, ’i’,
’A’, ’B’, ’C’.
Considerăm că avem la dispoziţie două variabile ce fac parte din acelaşi tip set
numite m_1 şi m_2.
Operaţiile matematice specifice lucrului cu mulţimi sunt descrise în limbaj cu ajutorul
operatorilor următori:
+ operator binar care codifică operaţia de reuniune a două mulţimi.
* operator binar care codifică operaţia de intersecţie a douo mulţimi
- operator binar care codifică diferenţa a două mulţimi
14
in operator relaţional binar care codifică operaţia de apartenenţă a unui
element la o mulţime
<= operator relaţional binar, codifică operaţia de incluziune
<> operator relaţional binar, codifică operaţia de
inegalitate = operator relaţional binar, codifică operaţia de
egalitate
Exemplu:
Considerăm declaraţiile:
var a, b, c: cifre;
Operaţie Rezultat
a:=[0..2] a conţine elementele 0,1,2
b:=[12..14, 1..3] b conţine elementele 12,13,14,1,2,3
c:=a+b c conţine elementele 12,13,14, 0,1, 2, 3
c:=a*b c conţine elementele 1, 2
c:=a-b c conţine elementul 0
5 in a false
a<>b true
a<=b false
Exemplu:
program demonstrativ;
var
n, x, i: byte;
a: set of byte;
begin
a:=[];
writeln ('introduceţi cardinalul mulţimii');
readln(n);
for i:=1 to n do
15
begin
readln(x);
a:=a+[x];
end;
for i:= 0 to 255 do
if i in a then write(i,' ');
end.
Exemplu:
const
cifre: set of byte=[0..9]
vocale: set of ’A ’ . . ’Z ’ = [’A ’ , ’E ’, ’I ’, ’O ’, ’U ’]
Pentru a defini o constantă simplă a tipului mulţime se va specifica identificatorul şi
valoarea ei.
Exemplu:
const
cifre=[0..9]
vocale=[’A’, ’E’, ’I’, ’0’, ’U’]
16
5. Rezolvarea problemei
În program persoanele vor fi simbolizate prin poziţia pe care au stat iniţial, adică
inainte de ivirea conflictelor, spre exemplu persoana care a stat pe primul scaun va fi
persoana 1, persoana care a stat pe al doilea scaun va fi persoana 2 etc, soluţiile fiind
afişate sub forma x1 x2. . .x n cu x i є{1, 2, ..., n} unde nє[1, 10] adică soluţiile vor fi afişate
sub forma unor permutări ale mulţimii {1, 2, ..., n}, permutări care satisfac condiţia ca
modulul diferenţei a două valori vecine să nu fie 1, pentru că în acest caz înseamnă că
douo persoane aflate în conflict sunt vecine, caz în care permutarea respectivă nu ar
mai satisface condiţiile problemei, deci nu ar mai fi soluţie.
Iniţial persoanele sunt aşezte în succesiunea 1, 2, ..., n, iar între fiecare douo
persoane vecine se ivesc conflicte, fapt pentru care trbuiesc găsite toate modurile
posibile de reaşezare a persoanelor, astefel încât persoanele aflate în conflict să fie
despărţite, iar între ele să se afle una sau cel mult douo persoane.
Pentru aceasta se vor genera toate succesiunile (x1, x2, ..., xn), x i є{1, 2, ..., n} care
satisfac următoarele condiţii:
• x[i]≠x[j], oricare ar fi i, jє{1, 2, ..., n}, i≠j adică persoanele trebuie să fie diferite
pentru că în cazul în care x[i]=x[j] inseamnă că pe poziţiile i şi j în rând se află aceeaşi
persoană, ceea ce nu este posibil, iar i trebuie să fie diferit de j pentru că în caz contrar
am vorbi de acelaşi scaun şi ca urmare x[i]=x[j] pentru că x[i] şi x[j] sunt aceeaşi
persoană.
• x[i]≠x[i+1]±1, oricare ar fi iє{1, 2, ..., n} adică persoanele aflate în conflict nu pot sta
alături pentru că în cazul în care x[i]=x[i+1]±1, persoanele care au stat iniţial alături
17
(persoanele fiind simbolizate acum prin numărul de ordine pe care au stat iniţial) ar sta
şi acum alături spre exemplu persoanele care au stat iniţial pe poziţiile 1 şi 2, adică
persoana 1 respectiv persoana 2 nu au voie să stea pe poziţiile vecine i şi i+1.
Considerăm că persoana 2 se află pe poziţia i iar persoana 1 se află pe poziţia i+1. În
acest caz x[i]=x[i+1]-1 deci cele douo persoane aflate în conflict vor fi din ou vecine ca
şi în cazul în care persoana 1 va fi pe poziţia i iar persoana 2 pe poziţia i+1 pentru că
x[i]=x[i+1]+1.
• Dacă persoanele x[i] şi x[j] se află în conflict atunci ele nu pot fi separate decât prin
una sau douo persoane, deci între scaunele i şi j se pot afla unu sau douo scaune,
adică pentru oricare i, j din mulţimea {1, 2, ..., n} dacă |x[i]-x[j] |=1 atunci |i-j| este 2
sau 3.
De fapt această condiţie include condiţia anterioară.
În continuare vor fi prezentate douo metode de rezolvare a problemei, prima
folosind implementarea recursivă iar a doua cu implementare iterativă.
5.1. Metoda 1
Această metodă este metoda care foloseşte implementarea recursivă.
Variabilele globale utilizate în program:
- variabila n de tip integer reprezintă numarul de persoane ce sunt aşezate pe
scaune;
- variabila x de tip array; această variabilă este un tablou unidimensional (o stivă)
în care se vor construi soluţiile problemei;
Programul va folosi pentru a genera soluţiile douo subprograme şi anume:
• o funcţie booleană denumită ‘valid’ cu care se va testa dacă elementele situate în
stivă, la momentul apelului funcţiei, satisfac condiţiile problemei şi anume dacă
persoanele aflate în conflict sunt despărţite prin una sau douo persoane dar şi dacă
valoarea ultimului element introdus în stivă pe pooziţia k (v[k]) nu se mai găseşte în
stivă pe poziţii mai mici decât k pentru că o persoană nu poate sta pe două locuri
distincte în acelaşi timp;
• o procedură denumită ‘generare’ cu care se vor genera soluţiile problemei, folosindu-
se de apeluri recursive ale sale şi de apeluri ale funcţiei valid;
Funcţia valid
18
• se atriabuie valoarea true funcţiei adică iniţial se consideră că elementele din
stivă satisfac condiţiile cerute de problemă astfel încât nu va fi nevoie să se
modifice valoarea funcţiei decât în cazul în care se găseşte un element din stivă
care nu satisface condiţia, caz în care funcţia va lua valoarea false şi se va apela
procedura exit pentru a se ieşi forţat din funcţie;
• pentru fiecare element nou intodus în stivă se verifică dacă valoarea sa se mai
găseste în stivă, în caz contrar se va verifica dacă între el şi persoanele aflate în
conflict sunt situate una sau douo persoane.
Aceste acţiuni se vor realiza astfel:
- se va parcurge stiva de la primul element până la penultimul, adică până la
elementul de pe poziţia k-1, într-o instrucţiune repetitivă cu număr cunoscut de
paşi cu contorul i astefel: for i:=1 to k-1 do (unde k este parametrul funcţiei,
transmis prin referintă, el semnificând poziţia pe care sa introdus o valoare nouo
în stivă, valoare care trebuie să fie verificată pentru a descoperi dacă este validă
sau nu);
- pentru fiecare valoare a lui i se va verifica dacă elemntul de pe poziţia i în stivă
este egal cu ultimul element din stivă, adică cel de pe poziţia k, în caz afirmativ
funcţia va lua valoarea false (nu sunt satisfăcute condiţiile problemei) şi se va
apela procedura exit pentru a ieşi forţat din funcţia valid, pentru că este de ajuns
ca un singur element să nu respecte condiţiile problemei pentru ca, conţinutul
stivei să nu constituie o soluţie pentru problemă; în cazul în care elementul de pe
poziţia i nu este egal cu elementul de pe poziţia k se va verifica dacă modulul
diferenţei v[i]-v[k] este egal cu 1 (adică persoana v[i] se află în conflict cu
persoana v[k]) şi dacă modulul diferenţei i-k este egală cu 2 sau cu 3, adică
dacă între persoanele v[i] şi v[k] sunt una sau două persoane, apărând astfel mai
multe situaţii: o situaţie în care |v[i]-v[k] |≠1, caz în care nu are rost să se
verifice dacă între persoanele v[k] şi v[i] mai sunt una sau douo persoane, pentru
că cele două persoane nu sunt în conflict, o situaţie în care |v[i]-v[k] |=1 iar
|i-k| aparţine mulţimii {2,3} , adică sunt respectate condiţiile impuse de
problemă, caz în care valoarea funcţiei valid nu se modifică pentru că are deja
valoarea true, însă în cazul în care |i-k| nu aparţine mulţimii {2, 3} şi |
v[i]-v[k]|=1 înseamnă că între cele 2 persoane v[i] şi v[k], persoane aflate în
conflict, nu se află una sau douo persoane (cele douo persoane pot fi alăturate
sau între ele se pot afla mai mult de douo persoane şi în nici unul din cazuri nu
sunt îndeplinite condiţiile) fapt pentru care funcţia va lua valoarea false şi se va
ieşi din funcţie prin apelul procedurii exit;
Toate aceste acţiuni vor constituie corpul de instucţiuni al funcţiei după cum este
scris mai jos:
begin
valid:=true;
for i:=1 to k-1 do
if v[i]=v[k] then
begin
valid:=false;
exit;
end
19
else
if(abs(v[i]-v[k])=1) and not(abs(i-k) in [2,3]) then
begin
valid:=false;
exit;
end;
end;
Procedura generare
20
{1, 2, ..., n} pe care le testează cu ajutorul procedurii valid pentru a vedea care dintre
ele pot constitui soluţii pentru problemă.
În limbaj pascal toate aceste acţiuni sunt codificate ca mai jos, constituind corpul
de instrucţiuni ale procedurii generare.
begin
if k=n+1 then
begin
for j:=1 to n do
write(v[j],' ');
writeln;
end
else
for j:=1 to n do
begin
v[k]:=j;
if valid(k) then
generare(k+1);
end;
end;
Programul principal
21
După ce s-a introdus o valoare validă pentru n se va testa dacă aceasta este mai mare ca
3 sau, mai mică sau egală cu 3 pentru că dacă n este mai mare ca trei se pot rearanja
persoanele astfel încât să se despartă cele aflate în conflict, pe când pentru valori din
intervalul închis [1, 3] oricât am încerca, nu vom găsi un mod prin care să se despartă
persoanele afate în conflict. În cazul în care n este mai mare ca 3 se va afişa un mesaj
sugestiv după care se va apela generare(1) pentru a genera şi afişa soluţiile problemei,
rezultatul apărând ca în imaginea de mai jos unde pentru n s-a citit valoarea 4.
însă în cazul în care n este mai mic ca patru (din intervalul [1, 3]) , caz în care nu se pot
despărţi persoanele aflate în conflict, se va afişa un mesaj sugestiv, după cum se vede în
imagineade mai jos:
După toate acestea, pentru a putea citi rezultatul până la apăsarea tastei ‘enter’,
înainte de ‘end.’ se va apela procedura readln fără parametri.
Codificat în limbaj pascal programul principal va arăta astfel:
begin
22
repeat
write('n=');
readln(n);
if not (n in [1..10]) then
writeln('date eronate (n nu apartine [1, 10])');
until n in [1..10];
if n>3 then
begin
writeln('modurile posibile de rearanjare pe scaune ');
writeln('in scopul despartirii pesroanelor aflate');
writeln('in conflict prin una sau doua persoane sunt urmatoarele: ');
generare(1);
end
else
begin
writeln('pentru acest numar de persoane, nu se poate gasi un ');
writeln('alt mod de aranjare pe scaune in scopul despartirii ');
writeln('persoanelor aflate in conflict');
end;
readln;
5.1. Metoda 2
Procedura succ
23
Această procedură are un singur parametru transmis prin valoare şi anume
parametrul k de tip integer care reprezintă poziţia din stivă pentru care se va verifica
dacă se poate genera un succesor, iar la apel procedura va fi apelată cu parametrul k,
variabilă globală de tip integer al cărei rol a fost specificat mai sus.
Modul în care procedura verifică dacă, pentru poziţia k din stivă, se poate genera
un succesor, în caz afirmativ memorândul pe poziţia k este următorul: Se verifică dacă
valoarea de pe poziţia k este mai mică de cât n (pentru că nu putem avea valori mai mari
sau egale cu n în stivă datorită motivului că persoanele sunt numerotate cu valori de la
unu la n, iar în cazul în care valoarea de pe poziţia k va fi egală cu n orice succesor vom
genera acela va avea valoare mai mare ca n, ceea ce este imposibil), în caz afirmativ
incrementând valoarea de pe poziţia k din stivă (se generează un succesor), iar pentru că
sa generat un succesor variabila as va lua valoarea true. În cazul în care valoarea de pe
poziţia k din stivă nu este mai mică decât n, înseamnă că nu se poate genera un succesor
pentru acestă poziţie, motiv pentru care as va lua valoarea false.
Aceste acţiuni vor constitui corpul de instrucţiuni al procedurii, după cum este
scris mai jos:
begin
if v[k]<n then
begin
v[k]:=v[k]+1;
as:=true;
end
else
as:=false
end;
Funcţia valid
Funcţia are o variabilă locală şi anume variabila i de tip integer, variabilă ce va
fi folosită drept contor în parcurgerea stivei, element cu element, pentru a putea verifica
dacă toate elementele satisfac condiţiile problemei.
Modul în care se verifica dacă fiecare element al stivei virifică condiţiile
problemei este următorul:
• se atriabuie valoarea true funcţiei adică iniţial se consideră că elementele din
stivă satisfac condiţiile cerute de problemă astfel încât nu va fi nevoie să se
modifice valoarea funcţiei decât în cazul în care se găseşte un element din stivă
care nu satisface condiţia, caz în care funcţia va lua valoarea false şi se va apela
procedura exit pentru a se ieşi forţat din funcţie;
• pentru fiecare element nou intodus în stivă se verifică dacă valoarea sa se mai
găseste în stivă, în caz contrar se va verifica dacă între el şi persoanele aflate în
conflict sunt situate una sau douo persoane.
Aceste acţiuni se vor realiza astfel:
- se va parcurge stiva de la primul element până la penultimul, adică până la
elementul de pe poziţia k-1, într-o instrucţiune repetitivă cu număr cunoscut de
paşi cu contorul i astefel: for i:=1 to k-1 do (unde k este parametrul funcţiei,
24
transmis prin referintă, el semnificând poziţia pe care sa introdus o valoare nouo
în stivă, valoare care trebuie să fie verificată pentru a descoperi dacă este validă
sau nu);
- pentru fiecare valoare a lui i se va verifica dacă elemntul de pe poziţia i în stivă
este egal cu ultimul element din stivă, adică cel de pe poziţia k, în caz afirmativ
funcţia va lua valoarea false (nu sunt satisfăcute condiţiile problemei) şi se va
apela procedura exit pentru a ieşi forţat din funcţia valid, pentru că este de ajuns
ca un singur element să nu respecte condiţiile problemei pentru ca, conţinutul
stivei să nu constituie o soluţie pentru problemă; în cazul în care elementul de pe
poziţia i nu este egal cu elementul de pe poziţia k se va verifica dacă modulul
diferenţei v[i]-v[k] este egal cu 1 (adică persoana v[i] se află în conflict cu
persoana v[k]) şi dacă modulul diferenţei i-k este egală cu 2 sau cu 3, adică
dacă între persoanele v[i] şi v[k] sunt una sau două persoane, apărând astfel mai
multe situaţii: o situaţie în care |v[i]-v[k] |≠1, caz în care nu are rost să se
verifice dacă între persoanele v[k] şi v[i] mai sunt una sau douo persoane, pentru
că cele două persoane nu sunt în conflict, o situaţie în care |v[i]-v[k] |=1 iar
|i-k| aparţine mulţimii {2,3} , adică sunt respectate condiţiile impuse de
problemă, caz în care valoarea funcţiei valid nu se modifică pentru că are deja
valoarea true, însă în cazul în care |i-k| nu aparţine mulţimii {2, 3} şi |
v[i]-v[k]|=1 înseamnă că între cele 2 persoane v[i] şi v[k], persoane aflate în
conflict, nu se află una sau douo persoane (cele douo persoane pot fi alăturate
sau între ele se pot afla mai mult de douo persoane şi în nici unul din cazuri nu
sunt îndeplinite condiţiile) fapt pentru care funcţia va lua valoarea false şi se va
ieşi din funcţie prin apelul procedurii exit;
Toate aceste acţiuni vor constituie corpul de instucţiuni al funcţiei după cum este
scris mai jos:
begin
valid:=true;
for i:=1 to k-1 do
if v[i]=v[k] then
begin
valid:=false;
exit;
end
else
if(abs(v[i]-v[k])=1) and not(abs(i-k) in [2,3]) then
begin
valid:=false;
exit;
end;
end;
Programul principal
25
În programul principa va fi citită valoarea n, în cadrul unei instrucţiuni repetitive
cu număr necunoscut de paşi şi cu test final cu condiţia ca n să fie din intervalul închis
[1, 10], condiţie care este dată din enunţul problemi şi în funcţie de valoarea lui n se va
afişa un rezultat.
După cum am mai spus, citirea lui n se va face în cadrul unei instrucţiuni
repetitive cu număr necunoscut de paşi şi cu test final, pentru că o valoare validă pentru
n este o valoare din intervalul [1, 10], deci trebuie să citim valori până când se citeşte
una validă, moment în care se iese din instrucţiunea repetitivă. Am folosit o instrucţiune
repetitivă cu număr necunoscut de paşi, pentru că nu se ştie câte valori trebuiesc citite
până când se va citi una validă, şi cu test final pentru că mai întâi se citeşte o valoare
pentru n şi apoi se verifică dacă aceasta este validă. Dacă valoarea citită pentru n este
una din intervalul [1, 10] se va ieşi din instrucţiunea repetitivă (s-a îndeplinit condiţia),
dar dacă valoarea lui n nu este validă se va afişa mesajul ‘date eronate (n nu apartine
[1, 10])’ după care se va cere introducera altei valori pentru n, după cum se vede în
imaginea de mai jos unde s-a introdus pentru n valoarea 13.
După citirea valorii lui n se va verifica dacă aceasta este mai mare decât 3 sau
mai mică sau agală cu 3 pentru că în cazul în care n este mai mic sau egal cu 3 nu se pot
rearanja persoanele pe scaune pentru a le despărţi pe cele aflate în conflict pentru că
oricât am încerca, douo persoane aflate în conflict vor fi alături, asta în cazul în care
avem mai mult de o persoană, caz în care se va afişa mesajul un mesaj în cadrul a trei
instucţiuni writeln, rezultatul apărând ca în imaginea de mai jos:
26
În cazul în care n va fi mai mare ca 3 se va afişa un mesaj sugestiv după care se
va iniţializa valoarea lui k cu 1 (se începe construirea soluţiilor de pe primul nivel al
stivei) şi valoarea primului element din stivă cu 0 după care se intră într-o instrucţiune
repetitivă cu număr necunoscut de paşi cu test iniţial cu condiţia k>0 deoarece k va
avea valoarea 0 în cazul în care sau generat toate permutările mulţimii {1, 2, ..., n} şi
nu se mai poate genera un alt succesor pentru st[1]. În cadrul acestei instrucţiuni
repetitive se va căuta un succesor valid pentru v[k], dacă există, în cadrul unei
instrucţiuni repetitive cu număr necunoscut de paşi cu test final cu condiţia de ieşire că
sa găsit un succesor valid sau că nu se poate genera un succesor pentru această poziţie.
După ce sa işit din instrucţiunea repetitivă în care sa căutat un succesor valid se verifică
dacă sa gesit un succesor , adică dacă as are valoarea true, caz în care este şi valid
pentru că altfel nu sar fi terminat căutarea, iar dacă sa găsit unul se va verifica dacă
stiva este plină, pentru că în acest caz înseamnă că în stivă v avem o soluţie pentru
problemă, soluţie care va fi afişată element cu element, cu un spaţiu între fiecare
element, în cadrul unei instrucţiuni repetitive cu număr cunoscut de paşi cu contorul i,
după care se va trece pe următorul rând pe ecran pentru ca rezultatul să poată fi citit cu
uşurinţă, iar în cazul în care k nu va fi egal cu n (k va fi mai mic decât n), se va
incrementa valoarea lui k şi se va iniţializa cu 0 valoarea de pe poziţia k (noul k) din
stivă, urmând să se genereze un succesor pentru acestă poziţie. În cazul în care as nu a
avut valoarea true (nu sa găsit un succesor pentru valoarea de pe poziţia k din stivă) se
va decrementa valoarea lui k şi se va căuta un succesor pentru valoarea de pe poziţia k
(se va căuta un succesor pentru pentru valoarea de pe o poziţie mai jos în stivă). Toate
aceste intrucţiuni se vor repeta până când k va lua valoarea 0, moment în care se iese
din intrucţiunea repetitivă. Toate aceste intrucţiuni vor fi realizate în cazul în care n este
mai mare ca 3, însă în cazul în care n este mai mic sau egal cu 3 se va afişa un mesaj
sugestiv prin care se va spune că pentru valoarea cititită pentru n nu se pot rearanja
persoanele pe scaune astfel încât să se despartă persoanele aflate în conflict.
În cazul în care n este mai mare ca 3 se va afişa un mesaj sugestiv urmat de
rezultatul obţinut pentru valoare citită pentru n, aşa cum se vede în imaginea de mai jos
unde s-a introdus pentru n valoarea 6.
27
În limbaj pascal programul principal va fi scris ca mai jos:
begin
repeat
write('n=');
readln(n);
if not n in [1..10] then
writeln('date eronate (n nu apartine [1, 10])');
until n in [1..10];
if n>3 then
begin
writeln('modurile posibile de rearanjare pe scaune ');
writeln('in scopul despartirii pesroanelor aflate');
writeln('in conflict prin una sau doua persoane sunt urmatoarele: ');
k:=1;
v[1]:=0;
while k>0 do
begin
repeat
succ(k);
if as then
valid(k);
until (not as) or (as and valid(k));
if as then
if n=k then
begin
for i:=1 to n do
28
write(v[i],' ');
writeln;
end
else
begin
k:=k+1;
v[k]:=0;
end
else
k:=k-1;
end;
end
else
begin
writeln('pentru acest numar de persoane, nu se poate gasi un ');
writeln('alt mod de aranjare pe scaune in scopul despartirii ');
writeln('persoanelor aflate in conflict');
end;
readln;
end.
29
6. Textul sursă al programului
6.1. Metoda 1
program scaune;
var n:integer;
v:array[1..10] of integer;
function valid(k:integer):boolean;
var i:integer;
begin
valid:=true;
for i:=1 to k-1 do
if v[i]=v[k] then
begin
valid:=false;
exit;
end
else
if(abs(v[i]-v[k])=1) and not(abs(i-k) in [2,3]) then
begin
30
valid:=false;
exit;
end;
end;
procedure generare(k:integer);
var j:integer;
begin
if k=n+1 then
begin
for j:=1 to n do
write(v[j],' ');
writeln;
end
else
for j:=1 to n do
begin
v[k]:=j;
if valid(k) then
generare(k+1);
end;
end;
begin
repeat
write('n=');
readln(n);
if not (n in [1..10]) then
writeln('date eronate (n nu apartine [1, 10])');
until n in [1..10];
if n>3 then
begin
writeln('modurile posibile de rearanjare pe scaune ');
writeln('in scopul despartirii pesroanelor aflate');
writeln('in conflict prin una sau doua persoane sunt urmatoarele: ');
generare(1);
end
else
begin
writeln('pentru acest numar de persoane, nu se poate gasi un ');
writeln('alt mod de aranjare pe scaune in scopul despartirii ');
writeln('persoanelor aflate in conflict');
end;
readln;
end.
6.2. Metoda 2
31
program scaune;
var v:array [1..10] of byte;
n,k,i:integer;
as:boolean;
procedure succ(k:integer);
begin
if v[k]<n then
begin
v[k]:=v[k]+1;
as:=true;
end
else
as:=false
end;
function valid(k:integer):boolean;
begin
valid:=true;
for i:=1 to k-1 do
if v[i]=v[k] then
begin
valid:=false;
exit;
end
else
if(abs(v[i]-v[k])=1) and not(abs(i-k) in [2,3]) then
begin
valid:=false;
exit;
end;
end;
begin
repeat
write('n=');
readln(n);
if not n in [1..10] then
writeln('date eronate (n nu apartine [1, 10])');
until n in [1..10];
if n>3 then
begin
writeln('modurile posibile de rearanjare pe scaune ');
writeln('in scopul despartirii pesroanelor aflate');
writeln('in conflict prin una sau doua persoane sunt urmatoarele: ');
k:=1;
32
v[1]:=0;
while k>0 do
begin
repeat
succ(k);
if as then
valid(k);
until (not as) or (as and valid(k));
if as then
if n=k then
begin
for i:=1 to n do
write(v[i],' ');
writeln;
end
else
begin
k:=k+1;
v[k]:=0;
end
else
k:=k-1;
end;
end
else
begin
writeln('pentru acest numar de persoane, nu se poate gasi un ');
writeln('alt mod de aranjare pe scaune in scopul despartirii ');
writeln('persoanelor aflate in conflict');
end;
readln;
end.
33