题目
https://leetcode-cn.com/problems/remove-max-number-of-edges-to-keep-graph-fully-traversable/
分析
删除最多数目的边=保留最少数目的边
1.优先添加公共边
2.添加独占边
在使用并查集进行合并的过程中,我们每遇到一次失败的合并操作(即需要合并的两个点属于同一个连通分量),那么就说明当前这条边可以被删除,将答案增加 1。
代码
class Solution {
public int maxNumEdgesToRemove(int n, int[][] edges) {
UnionFind ufa=new UnionFind(n);
UnionFind ufb=new UnionFind(n);
int ans=0;
//节点下标从0开始
for(int[] e:edges){
e[1]--;
e[2]--;
}
//类型3的边
for(int[] e:edges){
if(e[0]==3){
//1.e[1],e[2]已连通 false ans++
//2.e[1],e[2]未连通,true
if(!ufa.union(e[1],e[2])){
ans++;//可以删除
}
//不管是否连通,复制一份到Bob
//1.Bob已连通,不动
//2.Bob未联通,合并
else{
ufb.union(e[1],e[2]);
}
}
}
//类型1,2
for(int[] e:edges){
//Alice的边
if(e[0]==1){
if(!ufa.union(e[1],e[2])){
ans++;
}
}
//Bob的边
else if(e[0]==2){
if(!ufb.union(e[1],e[2])){
ans++;
}
}
}
//a和b的连通分量不为1,说明不可完全遍历
if(ufa.setCount!=1||ufb.setCount!=1){
return -1;
}
return ans;
}
}
class UnionFind{
public int[] parent;
public int[] size;
public int setCount;//连通分量
public UnionFind(int n){
parent=new int[n];
size=new int[n];
Arrays.fill(size,1);
setCount=n;
for(int i=0;i<n;i++){
parent[i]=i;
}
}
public int find(int index){
if(parent[index]!=index){
parent[index]=find(parent[index]);
}
return parent[index];
}
public boolean union(int index1,int index2){
int a=find(index1);
int b=find(index2);
if(a==b){
return false;
}
if(size[a]<size[b]){
int tmp=a;
a=b;
b=tmp;
}
size[a]+=size[b];
parent[b]=a;
setCount--;
return true;
}
}