这是一个小伙试图学习最短路径,然后被克鲁斯卡尔暴打的故事。
然后偷偷打开b站学习了一波并查集。
名词解释:
合并,查找,集合。
合并:将两个集合合并为一个。
查找:早到该元素的根。
实现方法:
通过一个parent数据纪录他的根节点,默认规定他的根是自己。
查找的实现:
int unfind(int x)
{
if(fa[x]==x) {return x;}
else {
unfind(fa[x]);
}
}
合并的实现:
void unionn(int x,int y)
{
int xx=unfind(x);
int yy=unfind(y);
fa[xx]=yy;
}
分析:
通过上面的代码,并查集的基本功能可以实现。
但是,如果我们合并(1,2)(2,3)(3,4)(4,5)——(n-1,n)
father数组的值就为
father | 1 | 2 | 3 | 4 | 5 |
1 | 1 | 2 | 3 | 4 |
这时,我们查找5的根时,它要递归4次才能找的到。
那查找n就要找n-1次,这显然时间复杂度太高了。
通过观察,我们可以发现2,3,4,5的根都是1。
从上面的代码来看,只有unfind函数可以优化。
int unfind(int x)
{
if(fa[x]==-1)fa[x]=x;
if(fa[x]==x) {return x;}
else {
fa[x]=unfind(fa[x]);//压缩路径
return fa[x];
}
}
我们可以这样压缩路径。
这样每一次查找,就把他这条路径上的所有点的上一级变成了根。