题目描述
题目分析
非常惭愧,感觉自己有点畏难心理,看到是困难题第一个想法是自己想不出来。。。
因为自己认为自己做不出来,所以完全不能进行思考,稍微思考一下就觉得不行不行。
我也想到了分别用两个并查集判断各自可以去掉多少边,但是一想到还有公共边,就感觉一头乱麻,不知道从什么地方下手。
当时主要感觉困难的地方在于,如果两个人去掉的公共边不一样,则没有办法统一。
看了题解以后我觉得我这个想法离正确的思路已经非常近了,抓住公共边这个矛盾再进行思考应该就可以。
另一方面还应该有跳出思维定势的能力,不能因为题目中先说的是私有边再说的是公有边自己也只能这样思考,要把条件翻来覆去进行转换才行。
回过头观察公共边:很容易觉得公共边比私有边重要(因为公有边两个人都可以用
我当时也想到公共边比较重要,但是又想到两个人可能用的公共边不一样。这其实就是思维定势:主观觉得一定要先使用私有边,不够的再是使用公有边。
如果先尽量使用公有边再使用私有边的话一切都将豁然开朗。因为在图的连通中使用并查集就表征了边的极大诱导子图(好像是这么说,可能不准确,意思就是每个连通分量已经是最大了)。因此丢去的公有边无论是哪条都无所谓(不会影响连通情况)。然后再分别考虑私有边。
AC代码
class UnionSet {
public:int n;int setCount;vector<int> father;vector<int> size;UnionSet(int _n):n(_n),setCount(_n),father(_n),size(_n, 1) {iota(father.begin(), father.end(), 0);}UnionSet() {}int root(int x) {return x == father[x] ? x : father[x] = root(father[x]);}bool unite(int x, int y) {x = root(x);y = root(y);if (x == y) {return false;}if (size[x] < size[y]) {swap(x, y);}father[y] = x;size[x] += size[y];--setCount;return true;}
};
class Solution {
public:int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {for (auto &edge : edges) {--edge[1];--edge[2];}int ans = 0;UnionSet us(n);// UnionSet us_a(n);// UnionSet us_b(n);for (auto &edge : edges) {if (edge[0] == 3) {//遍历公共边if (us.unite(edge[1], edge[2])) {// us_b.unite(edge[1], edge[2]);} else {++ans;}}}//计算Alice的联通UnionSet us_a;us_a.n = n;us_a.father = us.father;us_a.setCount = us.setCount;us_a.size = us.size;for (auto &edge : edges) {if (edge[0] == 1) {if (us_a.unite(edge[1], edge[2])) {} else {++ans;}}}if (us_a.setCount != 1) {return -1;}//计算Bob的联通UnionSet us_b;us_b.n = n;us_b.father = us.father;us_b.setCount = us.setCount;us_b.size = us.size;for (auto &edge : edges) {if (edge[0] == 2) {if (us_b.unite(edge[1], edge[2])) {} else {++ans;}}}if (us_b.setCount != 1) {return -1;}return ans;}
};