First, what is the disjoint-set
In computer science, disjoint-set data structure of a tree for consolidation and deal with some problems disjoint sets of queries. There is a joint - lookup algorithm (union-find algorithm) defines two operation times for the data structures:
- Find: determining which subset of elements belonging. It can be used to determine whether the two elements belong to the same subset.
- Union: the two subsets and into a collection.
Second, the main operation
- Initialization: initialize each point where the collection of its own.
for(int i=1;i<=n;i++)
f[i]=i;
- Find: Find a set of elements are located, that is the root node.
int find(int x)
{
while(f[x]!=x)
x=f[x];
return x;
}
- Merge: The two sets of elements where combined into one collection.
void Union(int x1,int x2)
{
int t1=find(x1);
int t2=find(x2);
if(t1!=t2)
f[t2]=t1;
}
Third, optimization
The above code seems simple, but the time complexity of each find operation is O (H), H is the height of the tree, because we did not do special treatment to the tree, so the tree continues to merge tree may cause a serious imbalance, the worst case each node has only one child node.
Therefore, the find function employed in path compression .
int find(int x) //查找x元素所在的集合,回溯时压缩路径
{
if (x != f[x])
{
f[x] = find(f[x]);
//从x结点搜索到祖先结点所经过的结点都指向该祖先结点
}
return f[x];
}
Fourth, the template title
Luo Gu P3367 [template] disjoint-set
#include<bits/stdc++.h>
using namespace std;
int n,m;
int f[10002];
int find(int x)
{
if(x!=f[x])
f[x]=find(f[x]);
return f[x];
}
void Union(int x1,int x2)
{
int t1=find(x1);
int t2=find(x2);
if(t1!=t2) //祖先不一样
f[t2]=t1; //把t2的祖先变为x1的祖先t1
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=0;i<m;i++)
{
int z,x,y;
cin>>z>>x>>y;
if(z==1)
Union(x,y);
else
{
if(find(x)!=find(y))cout<<"N"<<endl;
else cout<<"Y"<<endl;
}
}
return 0;
}
Fifth, the minimum spanning tree
A connected graph with n vertices of the original image is minimal spanning tree link subgraph, all of the n nodes comprising original image, and there is minimal communication while keeping FIG.
Minimum spanning tree is actually referred to as minimum weight spanning tree.
Kruskal's algorithm
- The graph all the edges in accordance with weight in ascending order
- Traversing all edges sorted, if constitute loop, then the edge is added to the collection
- Until it finds the n-1 sides
#include<bits/stdc++.h>
using namespace std;
int n,m;
int s,maxm;
int p[100002];
struct node{
int u;
int v;
int c;
}info[100002];
bool cmp(node x1,node x2)
{
if(x1.c!=x2.c)return x1.c<x2.c;
else if(x1.u!=x2.u) return x1.u<x2.u;
else return x1.v<x2.v;
}
int find(int x) //查找x元素所在的集合,回溯时压缩路径
{
if (x!=p[x])
{
p[x]=find(p[x]);
}
return p[x];
}
void bcj(int x1,int x2)//把x2并入x1的集合
{
int t1,t2;//存储祖先节点
t1=find(x1);
t2=find(x2);
if(t1!=t2)p[t2]=t1;
}
int main()
{
cin>>n>>m;//n就是顶点数,m是边数
for(int i=1;i<=n;i++)
{
p[i]=i;
}
for(int i=0;i<m;i++)
{
cin>>info[i].u>>info[i].v>>info[i].c;
}
sort(info,info+m,cmp);
for(int i=0;i<m;i++)//遍历所有的边
{
if(find(info[i].u)!=find(info[i].v))
{
bcj(info[i].u,info[i].v);//把v并入u的集合
maxm=max(maxm,info[i].c);
}
}
cout<<n-1<<" "<<maxm;
return 0;
}