链接:https://leetcode-cn.com/problems/remove-max-number-of-edges-to-keep-graph-fully-traversable/
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 。
示例 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)
互不相同
思路:本题要求删除尽可能多的边,要求剩下的边对于两个人,可以遍历完整个图。也就是说,要求剩下的边,对于两者,都能构成一个连通图。
根据贪心想法,我们应该尽可能保留第三种边,因为第三种边对于Alice和Bob均可以遍历--简单证明:如果一条公共边正好连接了两个连通分量,那么如果采用公共边只需要一条边,而使用单人边则需要两条边。
于是解题策略大约如下:我们首先遍历公共边集合,尽可能添加公共边;接下来,分别对于Alice和Bob尝试添加多少条边可以构建连通图。连通性可以用并查集维护。
class Solution {
public:
int Find(int x, int Father[]){
return x == Father[x] ? x : Father[x] = Find(Father[x],Father);
}
bool Union(int Father[],int A, int B, int & sumPoints){
A = Find(A,Father);
B = Find(B,Father);
if(A != B){
Father[A] = B;
-- sumPoints;
return true;
}
return false;
}
int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
int Father[100010], Temporary[100010];
vector<vector<int>> AliceEdges, BobEdges;
int m = edges.size(), i, u, v, ans = 0, sumPoints = n, temporarySum;
//并查集初始化
for(i = 1; i <= n; ++ i){
Father[i] = i;
}
//使用公共边构建基础图
for(i = 0; i < m; ++ i){
switch(edges[i][0]){
case 1:AliceEdges.push_back(edges[i]);
break;
case 2:BobEdges.push_back(edges[i]);
break;
case 3:u = edges[i][1], v = edges[i][2];
if(!Union(Father, u, v, sumPoints)) {
++ ans;
}
break;
}
}
//Alice连通性判断
for(i = 1; i <= n; ++ i){
Temporary[i] = Father[i];
}
temporarySum = sumPoints;
m = AliceEdges.size();
for(i = 0; i < m; ++ i){
if(!Union(Temporary,AliceEdges[i][1],AliceEdges[i][2],temporarySum)) ++ ans;
}
if(temporarySum > 1) return -1;
//Bob连通性判断
for(i = 1; i <= n; ++ i){
Temporary[i] = Father[i];
}
temporarySum = sumPoints;
m = BobEdges.size();
for(i = 0; i < m; ++ i){
if(!Union(Temporary,BobEdges[i][1],BobEdges[i][2],temporarySum)) ++ ans;
}
if(temporarySum > 1) return -1;
return ans;
}
};