Sunteți pe pagina 1din 183

Facultatea de Matematic i Informatic

Lecii de pregtire Admitere 2016

Ruxandra Marinescu Ghemeci


verman@fmi.unibuc.ro
Graf neorientat: G = (V, E)
vrf (nod), muchie
gradul unui vrf
vrfuri adiacente
lan
ciclu
distan
Graf neorientat: G = (V, E)
graf conex
component conex
dou componente conexe
Graf orientat: G = (V, E)
vrf (nod), arc
gradul unui vrf - intern, extern
drum
circuit
Arbore
1
arbore cu rdcin
fiu, tat
ascendent, descendent 3 5 9
frunz
2 6 7 8

4
Matrice de adiacen
Liste de adiacen
List de muchii/arce
Construcia din lista de muchii

Intrare: n,m i muchiile


6
8
1 2
1 3
2 3
2 4
4 6
2 6
1 5
5 6
Construcia din lista de muchii
int a[20][20], n, m; var a:array[1..20,1..20] of integer;
n,m:integer;
void citire(){ procedure citire;
int i,j,x,y; var i,j,x,y:integer;
begin
cin>>n>>m; readln(n,m);
for(i=1;i<=n;i++) for i:=1 to n do
for(j=1;j<=n;j++) for j:=1 to n do
a[i][j]=0; a[i,j]:=0;

for(i=1;i<=m;i++){ for i:=1 to m do


cin>>x>>y; begin
a[x][y]=1; readln(x,y);
a[y][x]=1; //neorientat a[x,y]:=1;
} a[y,x]:=1; //neorientat
} end;
end;
Construcia din lista de muchii
int a[20][20], n, m; var a:array[1..20,1..20] of integer;
n,m:integer;
void citire(){ procedure citire;
int i,j,x,y; var i,j,x,y:integer;
begin
cin>>n>>m; readln(n,m);
for(i=1;i<=n;i++) for i:=1 to n do
for(j=1;j<=n;j++) for j:=1 to n do
a[i][j]=0; a[i,j]:=0;

for(i=1;i<=m;i++){ for i:=1 to m do


cin>>x>>y; begin
a[x][y]=1; readln(x,y);
a[y][x]=1; //neorientat a[x,y]:=1;
} a[y,x]:=1; //neorientat
} end;
end;
Determinarea gradului unui vrf
Determinarea gradului unui vrf

int grad(int x){ function grad(x:integer):integer;


int j,nr=0; var nr,j:integer;
for(j=1;j<=n;j++) begin
if(a[x][j]==1) nr:=0;
nr++; for j:=1 to n do
return nr; if a[x,j]=1 then
} inc(nr);
grad:=nr;
end;
Folosind tot matrice nxn pentru a le
memora
int l[100][100], n,m; var l: array[1..100,0..100] of integer;
//l[i][0]=gradul varfului i var n,m:integer;
void citire(){ procedure citire;
int i,j,x,y,g; var i,j,x,y,g:integer;
cin>>n>>m; begin
for(i=1;i<=m;i++){ readln(n,m);
cin>>x>>y; for i:=1 to n do l[i,0]:=0;
/*l[x][0]=gradul lui x=la for i:=1 to m do begin
al catelea vecin am ajuns*/ readln(x,y);
l[x][0]++; {l[x][0]=gradul lui x=la al catelea vecin am
l[x][l[x][0]]=y; ajuns}
//neorientat l[x,0]:=l[x,0]+1;
l[y][0]++; l[x,l[x][0]]:=y;
l[y][l[y][0]]=x; //neorientat
} l[y,0]:=l[y,0]+1; l[y,l[y,0]]:=x;
for(i=1;i<=n;i++){ end;
cout<<i<<": "; for i:=1 to n do begin
g=l[i][0]; write(i,': ');
for(j=1;j<=g;j++) g:=l[i,0];
cout<<l[i][j]<<" "; for j:=1 to g do write(l[i,j],' ');
cout<<endl; writeln;
}} end; end;
int l[100][100], n,m; var l: array[1..100,0..100] of integer;
//l[i][0]=gradul varfului i var n,m:integer;
void citire(){ procedure citire;
int i,j,x,y,g; var i,j,x,y,g:integer;
cin>>n>>m; begin
for(i=1;i<=m;i++){
readln(n,m);
cin>>x>>y; for i:=1 to n do l[i,0]:=0;
/*l[x][0]=gradul lui x=la for i:=1 to m do begin
al catelea vecin am ajuns*/ readln(x,y);
l[x][0]++; {l[x][0]=gradul lui x=la al catelea vecin
l[x][l[x][0]]=y; am ajuns}
//neorientat l[x,0]:=l[x,0]+1;
l[y][0]++; l[x,l[x][0]]:=y;
l[y][l[y][0]]=x; //neorientat
} l[y,0]:=l[y,0]+1; l[y,l[y,0]]:=x;
for(i=1;i<=n;i++){ end;
cout<<i<<": "; for i:=1 to n do begin
g=l[i][0]; write(i,': ');
for(j=1;j<=g;j++) g:=l[i,0];
cout<<l[i][j]<<" "; for j:=1 to g do write(l[i,j],' ');
cout<<endl; writeln;
}} end; end;
int l[100][100], n,m; var l: array[1..100,0..100] of integer;
//l[i][0]=gradul varfului i var n,m:integer;
void citire(){ procedure citire;
int i,j,x,y,g; var i,j,x,y,g:integer;
cin>>n>>m; begin
for(i=1;i<=m;i++){
readln(n,m);
cin>>x>>y; for i:=1 to n do l[i,0]:=0;
/*l[x][0]=gradul lui x=la for i:=1 to m do begin
al catelea vecin am ajuns*/ readln(x,y);
l[x][0]++; {l[x][0]=gradul lui x=la al catelea vecin
l[x][l[x][0]]=y; am ajuns}
//neorientat l[x,0]:=l[x,0]+1;
l[y][0]++; l[x,l[x][0]]:=y;
l[y][l[y][0]]=x; //neorientat
} l[y,0]:=l[y,0]+1; l[y,l[y,0]]:=x;
for(i=1;i<=n;i++){ end;
cout<<i<<": "; for i:=1 to n do begin
g=l[i][0]; write(i,': ');
for(j=1;j<=g;j++) g:=l[i,0];
cout<<l[i][j]<<" "; for j:=1 to g do write(l[i,j],' ');
cout<<endl; writeln;
}} end; end;
int l[100][100], n,m; var l: array[1..100,0..100] of integer;
//l[i][0]=gradul varfului i var n,m:integer;
void citire(){ procedure citire;
int i,j,x,y,g; var i,j,x,y,g:integer;
cin>>n>>m; begin
for(i=1;i<=m;i++){
readln(n,m);
cin>>x>>y; for i:=1 to n do l[i,0]:=0;
/*l[x][0]=gradul lui x=la for i:=1 to m do begin
al catelea vecin am ajuns*/ readln(x,y);
l[x][0]++; {l[x][0]=gradul lui x=la al catelea vecin
l[x][l[x][0]]=y; am ajuns}
//neorientat l[x,0]:=l[x,0]+1;
l[y][0]++; l[x,l[x][0]]:=y;
l[y][l[y][0]]=x; //neorientat
} l[y,0]:=l[y,0]+1; l[y,l[y,0]]:=x;
for(i=1;i<=n;i++){ end;
cout<<i<<": "; for i:=1 to n do begin
g=l[i][0]; write(i,': ');
for(j=1;j<=g;j++) g:=l[i,0];
cout<<l[i][j]<<" "; for j:=1 to g do write(l[i,j],' ');
cout<<endl; writeln;
}} end; end;
Folosind tipul vector - dinamic
#include<vector>
vector<int> l[100];
int n,m;
void citire(){
int i,j,x,y;
cin>n>>m;
for(i=1;i<=m;i++){
f>>x>>y;
l[x].push_back(y);

//neorientat
l[y].push_back(x);
}
for(i=1;i<=n;i++){
cout<<i<<": ";
for(j=0;j<l[i].size();j++)
cout<<l[i][j]<<" ";
cout<<endl;
}
}
Liste implementate - pointeri
struct nod{ int info; type elem=^nod;
nod* urm;}; nod=record info:integer;
nod* l[100]; nod* p; urm:elem;
int n,m; end;
void citire(){ var l: array[1..100] of elem; var p:elem;
int i,x,y; var n,m:integer;
cin>>n>>m; procedure citire;
for(i=1;i<=n;i++) var i,x,y:integer;
l[i]=NULL; begin
for(i=1;i<=m;i++){ readln(n,m);
cin>>x>>y; for i:=1 to n do l[i]:=nil;
p=new nod; for i:=1 to m do
p->info=y; begin
p->urm=l[x]; readln(x,y);
l[x]=p; new(p);
//neorientat p^.info:=y;
p=new nod; p^.urm:=l[x];
p->info=x; l[x]:=p; {neorientat}
p->urm=l[y]; new(p); p^.info:=x;
l[y]=p; p^.urm:=l[y]; l[y]:=p;
} end;
//afisare liste {afisare liste}
for(i=1;i<=n;i++){ for i:=1 to n do
cout<<i<<": "; begin
p=l[i]; write(i,': ');
while(p!=NULL){ p:=l[i];
cout<<p->info<<" "; while p<>nil do
p=p->urm; begin
} write(p^.info,' ');
cout<<endl; p:=p^.urm;
} end;
}//citire writeln;
end;
end;
1
Vector tata
Lista de fii
3 5 9
(descendeni direci)

2 6 7 8

4
Dat un vector tata asociat unui arbore (arbore
genealogic) s se determine:
1) rdcina arborelui
2) frunzele arborelui
3) un lan de la un vrf dat la rdcin, afiat
direct i invers = ascendenii unui vrf (afiai
de la tat n sus/ de la rdcin n jos)
4) nivelul (generaia) fiecrui vrf n arbore i
nlimea arborelui (=numrul de generaii-1)
Rdcina este vrful care are tata egal cu 0
int radacina(){ function radacina:integer;
int i; var i:integer;
for(i=1;i<=n;i++) begin
if(tata[i]==0) for i:=1 to n do
return i; if tata[i]=0 then
return 0; radacina:=i;
} end;
Frunzele sunt vrfurile care nu apar n
vectorul tata
Varianta 1 Testm pentru fiecare vrf
i=1 n dac apare n vectorul tata

Complexitate?
void frunze1(){ procedure frunze1;
int i,j,ok; var i,j:integer;
for(i=1;i<=n;i++){ ok:boolean;
ok=1; begin
for(j=1;j<=n;j++) for i:=1 to n do
if (i==tata[j]) begin
ok=0; ok:=true;
if (ok) for j:=1 to n do
cout<<i<<' '; if i=tata[j] then
} ok:=false;
cout<<endl; if ok then
} write(i,' ');
end;
writeln;
end;
Varianta 1 Complexitate: O(n2)
Varianta 2 cu vector de apariii

Complexitate: O(n)
void frunze(){ procedure frunze;
int i; var i:integer;
int v[100]; v:array[1..100] of boolean;
begin
for(i=1;i<=n;i++) for i:=1 to n do
v[i]=0; v[i]:=true;

for(i=1;i<=n;i++) for i:=1 to n do


if(tata[i]>0) if tata[i]>0 then
v[tata[i]]=1; v[tata[i]]:=false;

for(i=1;i<=n;i++) for i:=1 to n do


if(v[i]==0) if v[i] then
cout<<i<<" "; write(i,' ');
cout<<endl; writeln;
} end;
void frunze(){ procedure frunze;
int i; var i:integer;
int v[100]; v:array[1..100] of boolean;
begin
for(i=1;i<=n;i++) for i:=1 to n do
v[i]=0; v[i]:=true;

for(i=1;i<=n;i++) for i:=1 to n do


if(tata[i]>0) if tata[i]>0 then
v[tata[i]]=1; v[tata[i]]:=false;

for(i=1;i<=n;i++) for i:=1 to n do


if(v[i]==0) if v[i] then
cout<<i<<" "; write(i,' ');
cout<<endl; writeln;
} end;
void frunze(){ procedure frunze;
int i; var i:integer;
int v[100]; v:array[1..100] of boolean;
begin
for(i=1;i<=n;i++) for i:=1 to n do
v[i]=0; v[i]:=true;

for(i=1;i<=n;i++) for i:=1 to n do


if(tata[i]>0) if tata[i]>0 then
v[tata[i]]=1; v[tata[i]]:=false;

for(i=1;i<=n;i++) for i:=1 to n do


if(v[i]==0) if v[i] then
cout<<i<<" "; write(i,' ');
cout<<endl; writeln;
} end;
Se urc n arbore de la x la rdcin folosind
vectorul tata
//de la x la radacina {de la x la radacina}
void drum(int x) procedure drum(x:integer);
{ begin
while(x!=0){ while x<>0 do
cout<<x<<" "; begin
x=tata[x]; write(x, ' ');
} x:=tata[x];
cout<<endl; end;
} writeln;
end;
//de la x la radacina {de la x la radacina}
void drum(int x) procedure drum(x:integer);
{ begin
while(x!=0){ while x<>0 do
cout<<x<<" "; begin
x=tata[x]; write(x, ' ');
} x:=tata[x];
cout<<endl; end;
} writeln;
end;

//de la radacina la x {de la radacina la x}


void drumRec(int x) procedure drumRec(x:integer);
{ begin
if(x!=0){ if x<>0 then
drumRec(tata[x]); begin
cout<<x<<" "; drumRec(tata[x]);
} write(x, ' ');
} end;
end;
Varianta 1:
pentru fiecare vrf determinm lanul pn la
rdcin i lungimea acestuia
nivelul unui vrf = nivelul tatlui + 1;
//de la x la radacina
int drumN(int x)
{
int k=0;
while(tata[x]!=0){
x=tata[x];
k++;
}
return k;
}
Varianta 1: recursiv

int niv1[100]={0}; //in main


int nivmax=0;
//functie care returneaza nivelul lui x niv1[radacina()]=0;
int drumNiv(int x){
if(tata[x]==0) //radacina for(i=1;i<=n;i++){
return 0; niv1[i]=drumNiv(i);
return 1+drumNiv(tata[x]); if (niv1[i]>nivmax)
} nivmax=niv1[i];
}
Varianta 1: Complexitate
Varianta 1:
O(n2)

Cum evitm parcurgerea de mai multe ori a


unui lan (i trecerea de mai multe ori pe la
acelai vrf)?
Varianta 1 mbuntiri
putem memora nivelurile deja calculate ale
vrfurilor ntr-un vector, pentru a evita trecerea
de mai multe ori prin acelai vrf i recalcularea
nivelului acestuia
int niv1[100]={0};

//functie care returneaza nivelul lui x


int drumNiv(int x){
if(tata[x]==0) //radacina
return 0;
if(niv1[x]==0)//necalculat
niv1[x]= 1+drumNiv(tata[x]);
return niv1[x];
}
int niv1[100]={0}; //in main
int nivmax=0;
//functie care returneaza nivelul lui x niv1[radacina()]=0;
int drumNiv(int x){
if(tata[x]==0) //radacina for(i=1;i<=n;i++){
return 0; niv1[i]=drumNiv(i);
if(niv1[x]==0)//necalculat if (niv1[i]>nivmax)
niv1[x]= 1+drumNiv(tata[x]); nivmax=niv1[i];
return niv1[x]; }
}
Varianta 1 mbuntit:
O(n)
Varianta 2: Parcurgem arborele de la rdcin
Similar parcurgerii grafurilor
Parcurgere n lime -> parcurgere pe niveluri a
arborelui
Este mai eficient n acest caz s reprezentm
arborele cu liste de fii
Concluzii:
Reprezentarea unui arbore cu vectorul tata
permite o parcurgere mai uoar a arborelui de
la frunze spre rdcin
Putem parcurge arborele i pornind din rdcin
i folosi parcurgeri generale de grafuri - lime
(pe niveluri) i adncime - dar atunci este mai
eficient s folosim ca reprezentare liste de fii /
liste de adiacen (pe care le putem obine din
vectorul tata)
int l[100][100], n; var l: array[1..100,0..100] of integer;
void tata_fii(){ var n:integer;
int i,j,x,y,g; procedure tata_fii;
for(i=1;i<=n;i++) var i,j,x,y,g:integer;
if(tata[i]>0){ begin
//muchie (tata[i],i) for i:=1 to n do l[i,0]:=0;
x=tata[i]; for i:=1 to n do
y=i; if tata[i]<>0 then begin
l[x][0]++; {muchie (tata[i],i)}
l[x][l[x][0]]=y; x:=tata[i];
} y:=i;
l[x,0]:=l[x,0]+1;
for(i=1;i<=n;i++){
l[x,l[x][0]]:=y;
cout<<i<<": ";
end;
g=l[i][0];
for(j=1;j<=g;j++) for i:=1 to n do begin
cout<<l[i][j]<<" "; write(i,': ');
cout<<endl; g:=l[i,0];
} for j:=1 to g do write(l[i,j],' ');
} writeln;
end;
end;
Dat un vector tata asociat unui arbore s se
determine:
1) gradul unui vrf x dat
2) toate vrfurile de pe un nivel p dat
3) cea mai apropiat frunz de rdcin i un lan
de la rdcin la aceasta
Dat un vector tata cu elementele aparinnd
mulimii {0,1,,n}, s se determine dac exist un
arbore cu vectorul tata asociat egal cu vectorul dat
(admitere 2007)
Trebuie ca
vectorul s aib un singur element egal cu 0
din rdcin s se poat ajunge n orice vrf
sau, echivalent, din orice vrf s se poat ajunge
n rdcin mergnd din tat n tat
Trebuie ca
vectorul s aib un singur element egal cu 0
din rdcin s se poat ajunge n orice vrf
sau, echivalent, din orice vrf s se poat ajunge
n rdcin mergnd din tat n tat
Idee similar cu cea de la calculul nlimii:
pornim dintr-un vrf i urcnd spre rdcin
marcm vrfurile prin care trecem
int acc[100]={0}; int validUrcare(){
int viz[100]={0}; int i;
/*acc[i]=1 i este accesibil for(i=1;i<=n;i++)
din radacina {viz[i]=0;acc[i]=0;}
viz[i]=1 i a fost vizitat*/ for(i=1;i<=n;i++){
if(accesibil(i)==0)
int accesibil(int x){ return 0;
if(tata[x]==0) return 1; }
if(viz[x]==0){ return 1;
viz[x]=1; }
acc[x]=accesibil(tata[x]);
}
return acc[x];
}
Ca i la calculul nlimii, sunt posibile i alte
abordri:
putem verifica i invers, dac din rdcin se
poate ajunge n orice vrf - parcurgem
arborele pornind din rdcin i verificm n
final dac au fost vizitate toate vrfurile
liste de fii
Tem - Dat un vector tata asociat unui arbore i
dou vrfuri x i y, s se determine cel mai
apropiat ascendent (strmo) comun celor dou
vrfuri
Convenie: dac x este ascendentul lui y atunci x
este considerat cel mai apropiat ascendent comun
al celor dou vrfuri
Tem - Dat un vector tata asociat unui arbore i
dou vrfuri x i y, s se determine cel mai
apropiat ascendent (strmo) comun celor dou
vrfuri

Idee:
- Marcm x i ascendenii lui x
- Urcm din y spre rdcin pn la primul vrf
marcat
Parcurgere = o modalitate prin care, plecnd
de la un vrf de start i mergnd pe
arce/muchii s ajungem la toate vrfurile
accesibile din s
Un vrf v este accesibil din s dac exist un
drum/lan de la s la v n G.
Idee: Dac
u este accesibil din s
uvE(G)
atunci v este accesibil din s.
(din aproape n aproape)
Parcurgerea n lime (BF = breadth first)

Parcurgerea n adncime (DF = depth first)


Parcurgerea n lime: se viziteaz
- vrful de start s
- vecinii acestuia
- vecinii nevizitai ai acestora
etc
7
4
5

1 9
8

3 2

6
7
4 1
5

1 9
8

3 2

135926478
7
4 1
5

1 9
8

3 2

135926478
7
4 1
5

1 9 3 5 9
8

3 2

135926478
7
4 1
5

1 9 3 5 9
8

3 2

135926478
7
4 1
5

1 9 3 5 9
8

3 2

1 3 5 9 6 42 7 8
7
4 1
5

1 9 3 5 9
8

3 2 2 6

1 35926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6

13 5926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6

135 926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135 926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

1359 26478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

13592 6478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926 478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

1359264 78
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926478
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

13592647 8
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

135926478
Vrfurile vizitate trebuie marcate:

1, dac i a fost vizitat


viz[i] =
0, altfel
Arcele/muchiile folosite pentru a descoperi
vrfuri noi accesibile din s formeaz un arbore:
tata[j] = acel vrf i din care este descoperit
(vizitat) j
Dac dorim i determinarea de lanuri
(!!minime) de la rdcin la alte vrfuri putem
reine n plus:
tata[j] = acel vrf i din care este descoperit
(vizitat) j
niv[i] = nivelul lui i n arborele asociat
parcurgerii
= distana de la s la i
7
4 1
5

1 9 3 5 9
8

3 2 2 6 4 7 8

6
for(i=1;i<=n;i++) {
viz[i]=0;
Iniializri tata[i]=0;
d[i]=32000;
pentru i=1,n executa }
viz[i]0
tata[i]0
niv[i]
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
d[j] d[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
d[j] d[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
d[j] d[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
d[j] d[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
d[j] d[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
d[j] d[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
int n;
int a[20][20];
int viz[20],tata[20],niv[20];
Iniializri int p,u,c[20];

pentru i=1,n executa for(i=1;i<=n;i++) {


viz[i]0 viz[i]=0;
tata[i]0 tata[i]=0;
niv[i] d[i]=32000;
}
int n;
int a[20][20];
int viz[20],tata[20],niv[20];
Iniializri int p,u,c[20];

pentru i=1,n executa for(i=1;i<=n;i++) {


viz[i]0 viz[i]=0;
tata[i]0 tata[i]=0;
niv[i] niv[i]=n;
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; d[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; d[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 d[j]=d[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 niv[j]=niv[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(j=1;j<=n;j++)
pentru j vecin al lui i
if(a[i][j]==1)
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 niv[j]=niv[i]+1;
}
}
}
procedure BF(s) void bf(int s){
coada C ; int p,u,i,j;
adauga(s, C) p = u = 1; c[1]=s;
viz[s] 1; niv[s] 0 viz[s]=1; niv[s]=0;
cat timp C executa while(p<=u){
i extrage(C); i=c[p]; p=p+1;
afiseaza(i); cout<<i<<" ";
for(k=1;k<=l[i][0];k++)
pentru j vecin al lui i
{ j=l[i][k];
daca viz[j]=0 atunci if(viz[j]==0){
adauga(j, C) u=u+1; c[u]=j;
viz[j] 1 viz[j]=1;
tata[j] i tata[j]=i;
niv[j] niv[i]+1 niv[j]=niv[i]+1;
}
}
}
Matrice de adiacen O(|V|2)

Liste de adiacen O(|V|+|E|)


Dat un graf orientat i dou vrfuri u i v, s
se determine un drum minim de la u la v

void lant(int x){ void lantr(int x){


while(x!=0){ if(x!=0){
cout<<x<<" "; lantr(tata[x]);
x=tata[x]; cout<<x<<" ";
} }
} }
Se apeleaz bf(u), apoi se afieaz drumul de la
u la v folosind vectorul tata (ca la arbori), dac
exist
Se apeleaz bf(u), apoi se afieaz drumul de la
u la v folosind vectorul tata (ca la arbori), dac
exist
bf(u);
if(viz[v] == 1)
drum(v);
else
cout<<nu exista drum;

unde funcia drum este cea de la arbori:


Se apeleaz bf(u), apoi se afieaz drumul de la
u la v folosind vectorul tata (ca la arbori), dac
exist
bf(u);
if(viz[v] == 1)
drum(v);
else
cout<<nu exista drum;

unde funcia drum este cea de la arbori:


void drum(int x){ void drumRec(int x){
while(x!=0){ if(x!=0){
cout<<x<<" "; drumRec(tata[x]);
x=tata[x]; cout<<x<<" ";
} }
} }
Parcurgerea bf(u) se poate opri atunci cnd
este vizitat v
Dac n loc de graf avem un arbore dat prin
vectorul tata:
putem folosi parcurgerea BF din rdcina
arborelui pentru a determina nivelul fiecrui vrf
i nlimea arborelui
putem construi matricea de adiacen sau listele
de adiacen/de fii asociate arborelui
o nou soluie pentru problemele anterioare
de la arbori
S se verifice dac un graf dat este conex

ok=1;
for(i=1;i<=n;i++)
if(viz[i]==0)
ok=0;
Graful este conex dac, prin apelul parcurgerii din
vrful 1, sunt vizitate toate vrfurile
Graful este conex dac, prin apelul parcurgerii din
vrful 1, sunt vizitate toate vrfurile

bf(1);
ok=1;
for(i=1;i<=n;i++)
if(viz[i]==0)
ok=0;
if(ok==1)
cout<<conex;
else
cout<<neconex;
ntr-un grup de n persoane se cunosc
perechile de persoane care pot comunica
direct.

a) S se care este numrul maxim de persoane


din grup care pot comunica oricare dou,
direct sau prin intermediari

b) S se afieze persoanele cele mai influente


din grup. O persoan este considerat mai
influent dect alta dac poate comunica
direct cu mai multe persoane
Idee: Asociem grupului un graf n care
vrfurile sunt persoane i muchiile unesc
persoane care pot comunica direct.
Idee: Asociem grupului un graf n care
vrfurile sunt persoane i muchiile unesc
persoane care pot comunica direct.
o a) Problema este echivalent cu a
determina componenta conex cu
numrul maxim de vrfuri n graful
asociat
o b) Problema este echivalent cu a
determina vrfurile de grad maxim -
tem
o Modificm bf(s) astfel nct s returneze
numrul de vrfuri vizitate
o Modificm bf(s) astfel nct s returneze
numrul de vrfuri vizitate
o Apelm funcia bf pentru fiecare vrf
nevizitat anterior pentru a determina
componentele conexe ale grafului i
reinem valoarea maxim returnat
int n, a[20][20], viz[20]; //in main
int p,u,c[20]; int nr,nrmax=0;
int bf_nr(int s){ for(i=1;i<=n;i++)
int p,u,i,j,nr=0; if(viz[i]==0){
p = u = 1; c[1]=s; nr=bf_nr(i);
viz[s]=1; if(nr>nrmax)
while(p<=u){ nrmax=nr;
i=c[p]; p=p+1; }
nr++; //cout<<i<<" "; cout<<nr. max:"<<nrmax<<endl;
for(j=1;j<=n;j++)
if(a[i][j]==1)
if(viz[j]==0){
u=u+1; c[u]=j;
viz[j]=1;
}
}
return nr;
}
int n, a[20][20], viz[20]; //in main
int p,u,c[20]; int i,nr,nrmax=0;
int bf_nr(int s){ for(i=1;i<=n;i++)
int p,u,i,j,nr=0; if(viz[i]==0){
p = u = 1; c[1]=s; nr=bf_nr(i);
viz[s]=1; if(nr>nrmax)
while(p<=u){ nrmax=nr;
i=c[p]; p=p+1; }
nr++; //cout<<i<<" "; cout<<nr. max:"<<nrmax<<endl;
for(j=1;j<=n;j++)
if(a[i][j]==1)
if(viz[j]==0){
u=u+1; c[u]=j;
viz[j]=1;
}
}
return nr;
}
Reguli - Olimpiada de Informatic etapa pe sector 2013

Ionu a cumprat un joc format din componentele necesare


asamblrii unui obiect. A studiat prospectul jocului n care sunt
precizate etapele pe care trebuie s le urmeze pentru o asamblare
corect a obiectului. Ionu a observat c nu este dat ordinea exact
a etapelor, ci se precizeaz ce etape de asamblare trebuie realizate
naintea altora. Ionu trebuie s asambleze obiectul n n etape,
numerotate de la 1 la n, respectnd regulile de asamblare prevzute
n prospect. Astfel, daca sunt trei etape i etapa 2 trebuie efectuat
neaprat naintea etapei 3, atunci o ordine corect a etapelor poate
fi: 1, 2, 3, sau 2, 1, 3, sau 2, 3, 1.
Cerin
Scriei un program care, cunoscnd numrul de etape i regulile de
succesiune ntre aceste etape, determin o succesiune corect de
etape prin care s se respecte regulile de asamblare din prospect.
reguli.in

7 9 - numrul de etape i numrul de reguli


2 1
2 4
1 7
4 7
6 7
5 6
3 6
5 3
1 4
o nti planificm activitile care nu trebuie
planificate naintea altor activiti
o Modelm problema cu grafuri
nti considerm vrfurile cu grad interior 0
o nti planificm activitile care nu trebuie
planificate naintea altor activiti
o Modelm problema cu grafuri
nti considerm vrfurile cu grad interior 0
- eliminm aceste vrfuri
o nti planificm activitile care nu trebuie
planificate naintea altor activiti
o Modelm problema cu grafuri
nti considerm vrfurile cu grad interior 0
- eliminm aceste vrfuri
- relum procedeul
o Observaii
- Vrfurile nu trebuie eliminate, ci doar sczute
gradele interne ale vecinilor
- La un pas pot deveni vrfuri cu grad intern 0 doar
acele vrfuri n care intrau arce cu o extremitate n
vrfuri eliminate la pasul anterior
- Implementare similar cu BF
#include<fstream>
using namespace std;
ifstream f("reguli.in");
ofstream g("reguli.out");
int a[100][100],x,y,n, gin[100],r,i,j;
//gin[i]=grad intern al lui i

int main(){
int c[100],p,u;
f>>n>>r;
//construim matricea de adiacenta coresp. regulilor
for(i=1;i<=r;i++){
f>>x>>y;
a[x][y]=1;
gin[y]++;
}
//adaugam toate elementele cu grad intern 0 in coada c
p=0;u=-1;
for(i=1;i<=n;i++)
if(gin[i]==0)
{
u++; c[u]=i;
}
/*extragem un element de grad 0 din coada,
il adaugam in solutie si il eliminam din graf = scadem
cu 1 gradul intern al vecinilor sai;
Daca se obtin astfel varfuri de grad intern 0, le
adaugam in coada c */

while(p<=u){
x=c[p]; p++;
g<<x<<" ";
for(j=1;j<=n;j++)
if(a[x][j]==1){
gin[j]--;
if(gin[j]==0){
u++;
c[u]=j;
}
}
}
Tem
1. Modificai programul astfel nct graful s fie
memorat cu liste de adiacen
2. Modificai programul astfel nct s fie
detectat existena de circuite (date incorecte
dependene circulare)
Varianta 2 folosim parcurgerea n adncime DF
o Cu ct un vrf este finalizat (explorat cu toate
vrfurile accesibile din el) mai trziu n
parcurgerea DF, cu att el este mai la nceput n
ordonare (n sortarea topologic)
o Adugm ntr-o stiv vrfurile, pe msura terminrii
explorrii lor (adic explorrii tuturor vecinilor)

o Eliminm vrfurile din stiv pe rnd i le afim


ntre participanii la un curs s-au legat relaii de
prietenie i comunic i n afara cursului.
Profesorul vrea s transmit un mesaj participanilor i
tie ce relaii de prietenie s-au stabilit ntre ei. El vrea
s contacteze ct mai puini participani, urmnd ca
acetia s transmit mesajul ntre ei.
Ajutai-l pe profesor s decid cui trebuie s transmit
iniial mesajul i s ataeze la mesaj o list n care s
arate fiecrui participant ctre ce prieteni trebuie s
trimit mai departe mesajul, astfel nct mesajul s
ajung la fiecare participant la curs o singur dat.
Idee modelm problema cu un graf neorientat
cui trebuie s transmit iniial mesajul = cte un vrf din
fiecare component conex

for(i=1;i<=n;i++)
if(viz[i]==0){
bf(i);
cout<<i<< ;
}
Idee modelm problema cu un graf
Traseul mesajului n fiecare component = lista de fii
pentru arborele bf memorat n vectorul tata (cte un
arbore pentru fiecare component)

- vezi programul pentru conversia de la vectorul


tata la lista de fii
Se viziteaz
- Iniial: vrful de start s - devine vrf curent
La un pas:
se trece la primul vecin nevizitat al vrfului
curent, dac exist
altfel
se merge napoi pe drumul de la s la vrful
curent, pn se ajunge la un vrf cu vecini
nevizitai
se trece la primul dintre acetia i se reia
procesul
Se viziteaz
- Iniial: vrful de start s - devine vrf curent
- La un pas:
se trece la primul vecin nevizitat al vrfului
curent, dac exist
altfel
se merge napoi pe drumul de la s la vrful
curent, pn se ajunge la un vrf cu vecini
nevizitai
se trece la primul dintre acetia i se reia
procesul
Se viziteaz
- Iniial: vrful de start s - devine vrf curent
- La un pas:
se trece la primul vecin nevizitat al vrfului
curent, dac exist
altfel
se merge napoi pe drumul de la s la vrful
curent, pn se ajunge la un vrf cu vecini
nevizitai
se trece la primul dintre acetia i se reia
procesul
Se viziteaz
- Iniial: vrful de start s - devine vrf curent
- La un pas:
se trece la primul vecin nevizitat al vrfului
curent, dac exist
altfel
se merge napoi pe drumul de la s la vrful
curent, pn se ajunge la un vrf cu vecini
nevizitai
se trece la primul dintre acetia i se reia
procesul
7
4
5

1 9
8

3 2

6
7 1
4
5

1 9
8

3 2

6
7 1
4
5
3
1 9
8

3 2

6
7 1
4
5
3
1 9
8
2
3 2

6
7 1
4
5
3
1 9
8
2
3 2

6 9
7 1
4
5
3
1 9
8
2
3 2

6 9

4
7 1
4
5
3
1 9
8
2
3 2

6 9

8
7 1
4
5
3
1 9
8
2
3 2

6 9

8
7 1
4
5
3
1 9
8
2
3 2

6 9

8
7 1
4
5
3
1 9
8
2
3 2

6 9

4 7

8
7 1
4
5
3
1 9
8
2
3 2

6 9

4 7

8
7 1
4
5
3
1 9
8
2
3 2

6 9

4 7

8
7 1
4
5
3
1 9
8
2
3 2

6 9

4 7

8
7 1
4
5
3
1 9
8
2 6
3 2

6 9

4 7

8
7 1
4
5
3
1 9
8
2 6
3 2

6 9

4 7

8
7 1
4
5
3
1 9
8
2 6
3 2

6 9

4 7

8
7 1
4
5
3 5
1 9
8
2 6
3 2

6 9

4 7

8
7 1
4
5
3 5
1 9
8
2 6
3 2

6 9

4 7

8
7 1
4
5
3 5
1 9
8
2 6
3 2

6 9

4 7

8
void df(int i){
viz[i]=1;
cout<<i<<" ";
for(int j=1;j<=n ;j++)
if(a[i][j]==1)
if(viz[j]==0){
tata[j]=i;
df(j);
}
}

Apel:
df(s)
void df(int i){
viz[i]=1;
cout<<i<<" ";
for(int j=1;j<=n ;j++)
if(a[i][j]==1)
if(viz[j]==0){
tata[j]=i;
df(j);
}
}

Apel:
df(s)
void df(int i){
viz[i]=1;
cout<<i<<" ";
for(int j=1;j<=n ;j++)
if(a[i][j]==1)
if(viz[j]==0){
tata[j]=i;
df(j);
}
}

Apel:
df(s)
void df(int i){
viz[i]=1;
cout<<i<<" ";
for(int j=1;j<=n ;j++)
if(a[i][j]==1)
if(viz[j]==0){
tata[j]=i;
df(j);
}
}

Apel:
df(s)
void df(int i){
viz[i]=1;
cout<<i<<" ";
for(int j=1;j<=n ;j++)
if(a[i][j]==1)
if(viz[j]==0){
tata[j]=i;
df(j);
}
}

Apel:
df(s)
Dat un graf neorientat, s se verifice dac
graful conine cicluri i, n caz afirmativ,
s se afieze un ciclu al su
Marinescu Ghemeci Ruxandra

S-ar putea să vă placă și