Documente Academic
Documente Profesional
Documente Cultură
Enunt:
https://infoarena.ro/problema/disjoint
https://www.pbinfo.ro/probleme/3338/disjoint
Solutia 1: O(N*M)
Problema se poate rezolva reprezentand multimile ca liste inlatuite.
Cand va trebui sa verificam daca 2 elemente se afla in aceeasi multime luam
fiecare element si parcurgem lista lui pana ajungem la sfarsit. Daca pentru
ambele noduri am ajuns la acelasi element atunci ele se afla in aceeasi
multime, altfel nu. Cand vrem sa unim 2 multimi alegem elementul de sfarsit
al primei multimi si il conectam la inceputul celeilalte liste.
Aceasta abordare are complexitatea O(N) pe operatie si se dovedeste
ineficienta.
Solutia 2:
O abordare eficienta este aceea de a reprezenta fiecare multime
(componenta conexa) ca pe un arbore cu radacina. Astfel pentru fiecare
operatie de tip 2 parcurgem arborele in sus din ambele elemente si daca la
sfarsit ajungem in aceeasi radacina atunci elementele noastre se afla in
aceeasi multime. Atunci cand vrem sa unim 2 multimi determinam radacinile
celor 2 arbori si le conectam printr-o muchie.
Momentan complexitatea timp a acestei solutii este tot O(N*M), dar
asupra acestei abordari putem aplica insa 2 optimizari care scad foarte mult
timpul de executie:
2. Compresia drumurilor:
#include<fstream>
using namespace std;
ifstream f("disjoint.in");
ofstream g("disjoint.out");
int tata[100002],dim[100002];
//in aceasta solutie nu mai aveam nevoie de vectorul dim
//insa l-am pastrat pentru a fi comparatia mai buna cu celelalte solutii
int tata_multime(int x)
{
if(x!=tata[x])
return tata_multime(tata[x]);
return x;
}
int main()
{
int n,m,p,x,y,i;
f>>n>>m;
for(i=1;i<=n;i++)
tata[i]=i,dim[i]=1; // initial fiecare nod este singurul dintr-o
// multime de 1 element si este tatal acelei
// multimi
for(i=1;i<=m;i++)
{
f>>p>>x>>y;
if(p==1)
unire(x,y); // unim multimile
else
{
if(tata_multime(x)==tata_multime(y)) // verificam daca sunt
// in aceeasi multime
g<<"DA"<<'\n';
else
g<<"NU"<<'\n';
}
}
return 0;
}
#include<fstream>
using namespace std;
ifstream f("disjoint.in");
ofstream g("disjoint.out");
int tata[100002],dim[100002];
int tata_multime(int x)
{
if(x!=tata[x])
return tata_multime(tata[x]);
return x;
}
int main()
{
int n,m,p,x,y,i;
f>>n>>m;
for(i=1;i<=n;i++)
tata[i]=i,dim[i]=1;
for(i=1;i<=m;i++)
{
f>>p>>x>>y;
if(p==1)
unire(x,y);
else
{
if(tata_multime(x)==tata_multime(y))
g<<"DA"<<'\n';
else
g<<"NU"<<'\n';
}
}
return 0;
}
#include<fstream>
using namespace std;
ifstream f("disjoint.in");
ofstream g("disjoint.out");
int tata[100002],dim[100002];
int tata_multime(int x)
{
if(x!=tata[x])
tata[x]=tata_multime(tata[x]); //facem optimizarea 2 si unim
//fiecare nod de pe lant cu
//radacina multimii
return tata[x];
}
Aplicatii
int tata_multime(int x)
{
if(x!=tata[x])
tata[x]=tata_multime(tata[x]);
return tata[x];
}
int main()
{
int n,m,i,k=0,s=0;
f>>n>>m;
for(i=1;i<=m;i++)
f>>v[i].x>>v[i].y>>v[i].c;
sort(v+1,v+m+1,cmp); // sortam muchiile
for(i=1;i<=n;i++)
tata[i]=i,dim[i]=1;
for(i=1;i<=m&&k<n-1;i++)
{
if(tata_multime(v[i].x)!=tata_multime(v[i].y))
{ // daca muchia actuala uneste 2 noduri din multimi diferite
unire(v[i].x,v[i].y); // unim cele 2 multimi
s+=v[i].c; // costul muchiei se aduga la costul apm-ului
sol[++k]=v[i]; // retinem muchia adaugata
}
}
g<<s<<'\n'<<n-1<<'\n'; // evident apm-ul are n-1 muchii
for(i=1;i<=k;i++) // iar k==(n-1)
g<<sol[i].x<<" "<<sol[i].y<<'\n';
return 0;
}