题目
原题链接:力扣(LeetCode)#1579
解析
还是并查集。。说实话,要做吐了。
本人的思想是维护两个连通集合Alice和Bob,一人一个。
关键点在于要进行两轮循环,首先判断公共边,如果公共边多了,就增加可以减去的边数。
第二轮循环进行独有边的判断。
考虑一下,两个顶点之间存在三种类型的边,并且该边不能全部省略,那么减去Alice和Bob两条独占边显然是最合算的。
代码
class Solution {
private:
int cnt1,cnt2,rest1,rest2;
int *a;//Alice
int *b;//Bob
public:
int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
int num=edges.size();
cnt1=cnt2=n;
int rest=0;
rest1=rest2=0;
int ans=0;
a=new int[cnt1+1];
b=new int[cnt2+1];
init(n);
for(int i=0;i<num;i++)
{
if(edges[i][0]==3)
{
merge(edges[i][1],edges[i][2],a,cnt1,rest);
merge(edges[i][1],edges[i][2],b,cnt2,rest);
}
}
for(int i=0;i<num;i++)
{
if(edges[i][0]==1)
{
merge(edges[i][1],edges[i][2],a,cnt1,rest1);
}
else if(edges[i][0]==2)
{
merge(edges[i][1],edges[i][2],b,cnt2,rest2);
}
}
if(cnt1==1&&cnt2==1)
{
return rest/2+rest1+rest2;//rest除以2的原因是公共边被加了两次,翻倍了
}
else
return -1;
}
void init(int n)
{
for(int i=1;i<=n;i++)
{
a[i]=i;
b[i]=i;
}
}
int find(int x,int* s)
{
if(s[x]==x)
return x;
else
return s[x]=find(s[x],s);
}
void merge(int x, int y,int* s,int& m,int& t)
{
int a1=find(x,s);
int a2=find(y,s);
if(a1!=a2)
{
s[a1]=a2;
m--;
}
else
{
t++;
}
}
};