题目
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) 互不相同
解答
思路
- 按照题目分析,首先有三种类型,A有,B有,共有。而如果要删除最多的边,则就是留下最少的边。那么,毫无疑问,首先从公用边开始合并,(类似这种连通图的问题,默认使用并查集了)。即分别定义两个并查集容器,uf_a,uf_b,分别进行合并
- 注意,在合并公共边时,需要两者都去调用Union函数。但是,答案自加只需要调用一次,详情看代码。
- 在首先添加完公共边之后,依次添加单独边。如果已经连通的边,则答案自加。
- 另外还需要检查是否全部连通,因此,可以直接调用并查集类中的count变量,直接判断其是否只有一个连通量。
代码
class UF
{
public:
vector<int> uf;
vector<int> rank;
vector<int> size;
int count;
UF(int n):size(n,1),uf(vector<int>(n)),rank(vector<int>(n)),count(n)
{
for(int i=0;i<n;++i)
{
uf[i]=i;
rank[i]=i;
}
}
int Find(int index)
{
return uf[index]==index?index:uf[index]=Find(uf[index]);
}
bool Union(int index1,int index2)
{
int find1 = Find(index1);
int find2 = Find(index2);
if(find1!=find2)
{
if(rank[find1]<rank[find2])
swap(find1,find2);
uf[find2] = find1;
if(rank[find1]==rank[find2]) ++rank[find1];
size[find1]+=size[find2];
--count;
return true;
}
return false;
}
};
class Solution {
public:
int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
UF uf_a(n),uf_b(n);
int ans=0;
for (auto& edge: edges)
{
--edge[1];
--edge[2];
}
for(auto &edge:edges)
{
//公共边
if(edge[0]==3)
{
if(!uf_a.Union(edge[1], edge[2])) ++ans;
else uf_b.Union(edge[1],edge[2]);
}
}
//单独
for(const auto& edge: edges)
{
if(edge[0]==1)
{
if(!uf_a.Union(edge[1],edge[2])) ++ans;
}
else if(edge[0]==2)
{
if(!uf_b.Union(edge[1],edge[2])) ++ans;
}
}
if(uf_a.count!=1||uf_b.count!=1) return -1;
return ans;
}
};