Documente Academic
Documente Profesional
Documente Cultură
#2971 tairos
Se dă un arbore cu N noduri, numerotate de la 1 la N. Arborele se va transforma astfel: la
oricare etapă fiecare nod de gradul 1 diferit de rădăcină din arborele actual se înlocuiește
cu un arbore identic cu cel dat inițial, iar la următoarea etapă procedeul se va relua pentru
arborele obținut, formându-se astfel un arbore infinit. În următoarele trei imagini se prezintă
un exemplu de arbore dat inițial, arborele obținut după prima etapă de prelungire a
frunzelor și arborele obținut după două etape de prelungire a frunzelor.
2 ≤ N ≤ 100
1 ≤ D ≤ 10.000
Un arbore este un graf neorientat, conex și fără cicluri.
Distanța dintre două noduri x și y ale unui arbore este egală cu numărul de muchii
ale unui lanț cu extremitățile în nodurile x și y, lanț format din noduri distincte.
Rădăcina va fi considerată ca fiind nodul 1;
Pentru teste în valoare de 17 puncte avem N = 3
Pentru teste în valoare de alte 22 puncte răspunsul este ≤ 10 000;
În concurs s-au acordat 10 puncte din oficiu. Aici se acordă pentru exemplele din
enunț.
tairos.in
4
3
1 2
3 1
3 4
tairos.out
5
3
1 2
3 1
3 5
4 3
tairos.out
tairos.in
5
25
2 1
2 3
1 4
5 2
tairos.out
33554432
Soluția de 90 de puncte
Soluția problemei constă în numărarea frunzelor în arborele inițial.
Fie FR[i] = numărul de frunze la distanța i de rădăcina 1 în arborele inițial
Fie NT[i] = numărul de noduri la distanța i de rădăcina 1 în arborele inițial care nu sunt
frunze.
Știm ca arborele inițial are doar 100 de noduri, deci acești doi vectori de mai sus FR și NT nu
vor fi deloc mari. În continuare vom defini V[i] ca fiind numărul de noduri la distanța i care
au fost cândva frunze în procesul de extindere al arborelui inițial.
Inițial V[0] = 1 și V[i] = 0 oricare i != 0 (caz particular de pornire. Dacă extindem un
nod izolat folosind tehnica din enunț vom obține exact arborele inițial).
Putem parcurge de la 0 la D vectorul V pentru a genera frunze la dreapta în vector folosind
tehnica programării dinamice. Mai exact, o recurență înainte de forma:
fiind la poziția i și având deja calculată valoarea V[i],
V[i + 1] += V[i] * FR[1]
V[i + 2] += V[i] * FR[2]
…..
V[i + adancime_arbore_initial] += V[i] * FR[adancime_arbore_initial]
În cuvinte, dacă la distanta i avem V[i] noduri și știm ca în arborele inițial
aveam FR[k] frunze la distanța k de rădăcina 1, atunci prelungind toate cele V[i] noduri
aflate la distanța i, vom obține V[i] * FR[k] noi frunze la distanța V[i + k].
Acum, pentru a afla exact câte noduri sunt la distanța D de rădăcina 1, trebuie sa nu uitam
de nodurile din arborele inițial care nu sunt frunze, cele reținute în vectorul NT.
Răspunsul este V[D] + V[D – 1] * NT[1] + V[D – 2] * NT[2] + ... + V[D -
a_a_i] * NT[a_a_i], unde a_a_i este adâncimea arborelui inițial.
Clarificare pentru formula de mai sus:
V[D] reprezintă numărul de noduri foste frunze aflate la distanța D de rădăcina (acestea
clar trebuie numărate).
V[D – 1] * NT[1] reprezintă nodurile-frunze aflate la distanța D-1 de rădăcină, pe care le
prelungim pentru ultima dată. Pentru fiecare arbore astfel prelungit trebuie sa număram
câte noduri ne-frunze (deoarece frunzele au fost deja numărate) are la distanța 1 –
informație reținută în NT[1].
V[D – k] * NT[k] exact ca mai sus.
#include <iostream>
#include <fstream>
ifstream fin("tairos.in");
ofstream fout("tairos.out");
lungime[nod]=adancime;
if(!viz[mat[nod][i]]) /// daca un nod nu a fost vizitat, atunci este fiul nodului
curent
viz[mat[nod][i]]=true;
tata[mat[nod][i]]=nod;
dfs(mat[nod][i], adancime+1,maxadanc);
int x,y;
fin>>N>>D;
fin>>x>>y;
mat[y][0]++;mat[y][mat[y][0]]=x;
int main()
citire(N,D,tata);
if (steril[i])
else
nfr=0;
for(int i=1;i<=N;i++)
nfr++;
nrfrunze[nfr]=frunze[i]; /// numarul frunzelor la
nrsol[0]=1;
if (distanta[j]<=i)
nrsol[i]=(nrsol[i]+(nrsol[i-distanta[j]]*nrfrunze[j])%R)%R; ///
construiesc valorile initiale pana la maxadanc
fout<<nrsol[D];
return 0;
#2968 conexidad
Fie un graf neorientat cu N noduri și M muchii, care NU este conex.
Să i se adauge grafului un număr minim de muchii, astfel încât acesta să devină conex.
Fie extra numărul de muchii nou-adăugate care sunt incidente cu nodul i, iar max_extra cea
i
mai mare dintre valorile extra , extra ,… , extra . Mulțimea de muchii adăugate trebuie să
1 2 N
1 ≤ N ≤ 100
0 ≤ M ≤ N*(N-1)/2
Nodurile grafului sunt numerotate de la 1 la N inclusiv.
Muchiile prezente în fișierul de intrare sunt distincte.
Pentru orice muchie [a,b] aflată în fișierul de intrare, avem a ≠ b.
Graful din fișierul de intrare nu este conex.
În cazul în care soluția afișată pentru un anumit test conectează graful cu număr minim
de muchii, dar nu minimizează valoarea lui max_extra, se vor acorda 50% din punctajul
pentru testul respectiv.
Dacă există mai multe soluții optime, se va admite oricare dintre acestea.
În concurs s-au acordat 10 puncte din oficiu. Aici se acordă pentru exemplele din enunț.
conexidad.in
4 2
1 2
4 2
conexidad.out
1
1
3 1
Graful este format din două componente conexe, cu noduri din mulțimea {1, 2, 4} respectiv
nodul izolat 3. După adăugarea muchiei (3,1) vom avea
valorile extra =1, extra =0, extra =1, extra =0, deci max_extra = 1. Se poate demonstra
1 2 3 4
5 1
3 4
conexidad.out
2
3
1 3
2 3
4 5
Graful este format din patru componente conexe, cu noduri din mulțimea {3, 4}, respectiv
nodurile izolate 1, 2 și 5. După adăugarea muchiilor (1,3), (2,3) și (4,5), vom avea
valorile extra =1, extra =1, extra =2, extra =1, extra =1, deci max_extra = 2. Se poate
1 2 3 4 5
#include<iostream>
#include<fstream>
ifstream fin("conexidad.in");
ofstream fout("conexidad.out");
int a[101][101],viz[101],ind,n,x,y,cnt,m,extra[101],laturi[200];
viz[x0]=cnt+1;
for(int j=1;j<=n;j++)
if(a[x0][j]&&!viz[j])
dfs(j);
void conex()
cnt=0;
int k=1,i;
while(k)
i=1;
while(viz[i]!=0&&i<=n)
i++;
if(i<=n)
dfs(i);
cnt++;
else
k=0;
}
}
int mn=100,pos=1;
for(int i=n;i>=1;i--)
if(extra[i]<=mn&&viz[i]==componenta)
mn=extra[i];
pos=i;
return pos;
int main()
fin>>n>>m;
for(int i=1;i<=m;i++)
fin>>x>>y;
a[x][y]=a[y][x]=1;
conex();
int cnt2=cnt;
for(int i=1;i<cnt2;i++)
int x,y;
x=minExtraPos(1);
y=minExtraPos(2);
a[x][y]=1;
a[y][x]=1;
extra[x]++;
extra[y]++;
laturi[++ind]=x;
laturi[++ind]=y;
for(int i=1;i<=n;i++)
viz[i]=0;
conex();
int mx=0;
for(int i=1;i<=n;i++)
if(extra[i]>mx)
mx=extra[i];
fout<<mx<<endl<<cnt2-1<<endl;
for(int i=1;i<=ind;i++)
fout<<laturi[i];
if(i%2==0)
fout<<endl;
else
fout<<" ";
return 0;