并查集
并查集
https://www.luogu.com.cn/problem/P3367
并查集问题非常经典,解法非常精妙
首先对每个元素做标号
数据结构就是一个数组,数组中存储的是对应根节点的标号
//初始化
for (int i=1;i<=k;i++) {
f[i]=i;
}
所谓并查集,也就只有两个操作,并和查
首先是查操作
int find(int k) {
//如果根节点是自己,那么返回
if(f[k]==k)return k;
//否则找父节点的根节点,并且做一下路径压缩,将父节点的根节点置为自己的根节点
return f[k]=find(f[k]);
}
然后是并操作
void merge(int a, int b) {
//把a的根节点挂到b的根节点上,如果只把a挂到b上,就无法顾及到a的根节点上的其他节点了
f[find(a)]=find(b);
}
非常巧妙,短短几行代码,实现了如此复杂而又高效的逻辑
带权并查集
无权的并查集应用范围还是比较有限,加上权重,就能实现更复杂的逻辑,例如leetcode 399. 除法求值
带上权重的话,就需要添加一个数组,存储权重值,初始化为1
在这道题中,权重是商,那么 w[i] 含义就是 N[i] = w[i] * N[f[i]]
for (int i=1;i<=k;i++) {
f[i]=i;
w[i]=1;
}
查操作和并操作
int find(int x) {
if (f[x]==x) return x;
int y=f[x];
int z=find(y);
//每进行一次find操作,w数组也被更新过了,因此用更新过的y再更新x
w[x]=w[x]*w[y];
return f[x]=z;
}
void merge(int a, int b, double k) {
int aa=find(a);
int bb=find(b);
f[aa]=bb;
// a/b=k a=w[a]*aa b=w[b]*bb w[aa]=aa/bb 推导可得
w[aa]=k*w[b]/w[a];
}

浙公网安备 33010602011771号