package com.heu.wsq.leetcode.bingchaji;
import java.util.ArrayList;
import java.util.List;
/**
* 1579. 保证图可完全遍历
* @author wsq
* @date 2021/1/27
* 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 。
*
* 链接:https://leetcode-cn.com/problems/remove-max-number-of-edges-to-keep-graph-fully-traversable
*/
public class MaxNumEdgesToRemove {
public int maxNumEdgesToRemove(int n, int[][] edges){
// 新增两个虚拟结点alice和bob
int ret = 0;
int alice = 0;
int bob = n + 1;
// 构建并查集对象
UnionFind unionFind = new UnionFind(2 * n + 2);
// 保存是否alice和bob是否与当前边相连
boolean aliceFlag = true;
boolean bobFlag = true;
// 单独处理公共边
List<int[]> otherList = new ArrayList<>();
for (int[] edge : edges) {
if (edge[0] == 3){
if (unionFind.isConnected(edge[1], edge[2])){
ret += 1;
continue;
}
unionFind.union(edge[1], edge[2]);
unionFind.union(bob + edge[1], bob + edge[2]);
if (aliceFlag && bobFlag){
unionFind.union(edge[1], alice);
unionFind.union(bob + edge[1], bob);
aliceFlag = false;
bobFlag = false;
}
}else{
otherList.add(edge);
}
}
for (int[] edge : otherList) {
if (edge[0] == 1){
boolean connected = unionFind.isConnected(edge[1], edge[2]);
if (connected){
ret += 1;
}else{
unionFind.union(edge[1], edge[2]);
if (aliceFlag){
unionFind.union(edge[1], alice);
}
}
}else{
boolean connected = unionFind.isConnected(bob + edge[1], bob + edge[2]);
if (connected){
ret += 1;
}else{
unionFind.union(bob + edge[1], bob + edge[2]);
if (bobFlag){
unionFind.union(bob, bob + edge[1]);
}
}
}
}
return unionFind.getSize(alice) == n + 1 && unionFind.getSize(bob) == n + 1 ? ret : -1;
}
private class UnionFind{
private int[] parent;
private int[] size;
public UnionFind(int n){
this.parent = new int[n];
this.size = new int[n];
for (int i = 0; i < n; i++){
this.parent[i] = i;
this.size[i] = 1;
}
}
public void union(int x, int y){
int rootX = find(x);
int rootY = find(y);
if (rootX == rootY){
return;
}
this.parent[rootX] = rootY;
this.size[rootY] += this.size[rootX];
}
public int find(int x){
if (x != this.parent[x]){
this.parent[x] = find(this.parent[x]);
}
return this.parent[x];
}
public int getSize(int x){
return this.size[find(x)];
}
public boolean isConnected(int x, int y){
return find(x) == find(y);
}
}
}
1579. 保证图可完全遍历(并查集)
最新推荐文章于 2021-10-25 19:11:05 发布