题目
Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3 种类型的边:
类型 1:只能由 Alice 遍历。
类型 2:只能由 Bob 遍历。
类型 3:Alice 和 Bob 都可以遍历。
给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。
返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。
示例1
输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
输出:2
解释:如果删除 [1,1,2] 和 [1,1,3] 这两条边,Alice 和 Bob 仍然可以完全遍历这个图。再删除任何其他的边都无法保证图可以完全遍历。所以可以删除的最大边数是 2
题解
- 由于Type3类型的边Alice和Bob都可以遍历,所以再构建连通分量的时候应该先将Type3类型的边连通
- Type3类型的边连通之后再分别针对与Alice和Bob进行连通Type1和Type2类型的边
- 构建两个并查集分别对应Alice与Bob
- 对于Alice与Bob两个并查集,连接Type3类型的边。
- 对Alice连接Type1类型的边,对Bob连接Type2类型的边
- 在连接的过程中如果,当前两个节点已被连通,则表示此时改变可以被删除
- 判断结束后alice与bob并查集内是否只能一个连通分量
参考代码
class Solution {
public int maxNumEdgesToRemove(int n, int[][] edges) {
int res = 0;
for(int[] edge : edges) {
edge[1]--;
edge[2]--;
}
UnionFind alice = new UnionFind(n);
UnionFind bob = new UnionFind(n);
for(int[] edge : edges) {
if(edge[0] == 3) {
if(alice.union(edge[1], edge[2])) {
bob.union(edge[1], edge[2]);
} else {
res++;
}
}
}
for(int[] edge : edges) {
if(edge[0] == 1) {
if(!alice.union(edge[1], edge[2])) {
res++;
} else {
alice.union(edge[1], edge[2]);
}
} else if(edge[0] == 2) {
if(!bob.union(edge[1], edge[2])) {
res++;
} else {
bob.union(edge[1], edge[2]);
}
}
}
if(alice.getCount() != 1 && bob.getCount() != 1) return -1;
return res;
}
class UnionFind {
int[] parent;
int[] rank;
int count;
public UnionFind(int n) {
parent = new int[n];
rank = new int[n];
this.count = n;
Arrays.fill(rank, 1);
for(int i = 0; i < n; i++) {
parent[i] = i;
}
}
public int getCount() {
return count;
}
public boolean union(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if(rootA == rootB) return false;
if(rank[rootA] < rank[rootB]) {
parent[rootA] = rootB;
} else {
if(rank[rootA] == rank[rootB]) {
rank[rootA]++;
}
parent[rootB] = rootA;
}
count--;
return true;
}
public int find(int index) {
if(index != parent[index]) {
return find(parent[index]);
}
return index;
}
}
}