題目描述
題目分析
非常慚愧,感覺自己有點畏難心理,看到是困難題第一個想法是自己想不出來。。。
因為自己認為自己做不出來,所以完全不能進行思考,稍微思考一下就覺得不行不行。
我也想到了分別用兩個并查集判斷各自可以去掉多少邊,但是一想到還有公共邊,就感覺一頭亂麻,不知道從什么地方下手。
當時主要感覺困難的地方在于,如果兩個人去掉的公共邊不一樣,則沒有辦法統一。
看了題解以后我覺得我這個想法離正確的思路已經非常近了,抓住公共邊這個矛盾再進行思考應該就可以。
另一方面還應該有跳出思維定勢的能力,不能因為題目中先說的是私有邊再說的是公有邊自己也只能這樣思考,要把條件翻來覆去進行轉換才行。
回過頭觀察公共邊:很容易覺得公共邊比私有邊重要(因為公有邊兩個人都可以用
我當時也想到公共邊比較重要,但是又想到兩個人可能用的公共邊不一樣。這其實就是思維定勢:主觀覺得一定要先使用私有邊,不夠的再是使用公有邊。
如果先盡量使用公有邊再使用私有邊的話一切都將豁然開朗。因為在圖的連通中使用并查集就表征了邊的極大誘導子圖(好像是這么說,可能不準確,意思就是每個連通分量已經是最大了)。因此丟去的公有邊無論是哪條都無所謂(不會影響連通情況)。然后再分別考慮私有邊。
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;}
};