LeetCode 每日一题1579. 保证图可完全遍历

1579. 保证图可完全遍历

Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3 种类型的边:

  • 类型 1:只能由 Alice 遍历。
  • 类型 2:只能由 Bob 遍历。
  • 类型 3:Alice 和 Bob 都可以遍历。

给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 uivi 之间存在类型为 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

示例 2:

在这里插入图片描述

输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]]
输出:0
解释:注意,删除任何一条边都会使 Alice 和 Bob 无法完全遍历这个图。

示例 3:

在这里插入图片描述

输入:n = 4, edges = [[3,2,3],[1,1,2],[2,3,4]]
输出:-1
解释:在当前图中,Alice 无法从其他节点到达节点 4 。类似地,Bob 也不能达到节点 1 。因此,图无法完全遍历。

提示:

  • 1 <= n <= 10^5
  • 1 <= edges.length <= min(10^5, 3 * n * (n-1) / 2)
  • edges[i].length == 3
  • 1 <= edges[i][0] <= 3
  • 1 <= edges[i][1] < edges[i][2] <= n
  • 所有元组 (typei, ui, vi) 互不相同

方法一:贪心 + 并查集

解题思路

依然是连通性的问题,此题的基础是保证图中的所有点对于两个人分别是连通的(并查集),在保证连通性的前提下尽量少使用边(贪心)。

  • 贪心:因为有「类型 3」的边存在,应该优先使用「类型 3」的边。
  • 并查集:使用两个并查集 ufAliceufBob 分别维护 Alice 和 Bob 的点的连通性。
  • 处理多余的边:遍历 edges 时,有 edges[i] 对应的两个点已经连通时,说明这是一条多余边

参考代码

public int maxNumEdgesToRemove(int n, int[][] edges) {
    
    
    UnionFind ufAlice = new UnionFind(n);
    UnionFind ufBob = new UnionFind(n);
    int ret = 0;
    // 图中的点是从角标 1 开始,转为从角标 0 开始
    // 优先使用类型 3 的边
    for (int[] edge : edges) {
    
    
        edge[1]--;
        edge[2]--;
        if (edge[0] == 3) {
    
    
            if (ufAlice.union(edge[1], edge[2])) {
    
    
                ufBob.union(edge[1], edge[2]);
            } else {
    
    
                ret++;
            }
        }
    }

    // 使用类型 1 和类型 2 的边
    for (int[] edge : edges) {
    
    
        if (edge[0] == 1) {
    
    
            if (!ufAlice.union(edge[1], edge[2])) {
    
    
                ret++;
            }
        } else if(edge[0] == 2) {
    
    
            if (!ufBob.union(edge[1], edge[2])){
    
    
                ret++;
            }
        }
    }
    return (ufAlice.getCount() == 1 && ufBob.getCount() == 1) ? ret : -1;
}

class UnionFind {
    
    
    private int[] parent;

    private int count;

    public UnionFind(int n) {
    
    
        count = n;
        parent = new int[n];
        for (int i = 0; i < n; i++) {
    
    
            parent[i] = i;
        }
    }

    public boolean union(int x, int y) {
    
    
        int rootX = find(x);
        int rootY = find(y);
        if (rootX == rootY) {
    
    
            return false;
        }
        count--;
        parent[rootX] = rootY;
        return true;
    }

    public int find(int x) {
    
    
        return parent[x] == x ? parent[x] : (parent[x] = find(parent[x]));
    }

    public int getCount() {
    
    
        return count;
    }
}

执行结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_27007509/article/details/113248188