給定一個陣列 edges,其中 edges[i]=[typei,ui,vi] 表示類型為 typei 的雙向邊連接節點 ui 和 vi,找出可以移除的最大邊數,使得移除後,圖仍然可以被 Alice 和 Bob 完全遍歷。如果從任何一個節點開始,Alice 和 Bob 都可以到達所有其他節點,則圖被 Alice 和 Bob 完全遍歷。
返回你可以移除的最大邊數,如果 Alice 和 Bob 不能完全遍歷整個圖則返回 −1。
思路:DSU(Disjoint Set Union)
題意的要求是移除最大數量的邊,使得整個圖是連通的,而求連通分量的問題可以使用 併查集(DSU) 來解決,分別對 Alice 和 Bob 創建兩個 DSU 類別,然後對於每條邊進行合併操作。
但由於有三種類型的邊,我們需要對邊進行分類,分別處理公共的邊、Alice 的邊和 Bob 的邊。首先,我們將給定的邊分為三組:公共的邊、Alice 的邊和 Bob 的邊。
classSolution: defmaxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -> int: lst = [[] for _ inrange(3)] for t, u, v in edges: lst[t-1].append((u-1, v-1)) ans = 0 uf1, uf2 = DSU(n), DSU(n) for u, v in lst[2]: # Common ifnot uf1.union(u, v) ornot uf2.union(u, v): ans += 1 for u, v in lst[0]: # Alice ifnot uf1.union(u, v): ans += 1 for u, v in lst[1]: # Bob ifnot uf2.union(u, v): ans += 1 return ans if uf1.cnt == 1and uf2.cnt == 1else -1
classDSU { public: vector<int> pa, sz; int cnt; DSU(int n) { pa.resize(n); iota(pa.begin(), pa.end(), 0); sz.assign(n, 1); cnt = n; } intfind(int x){ return pa[x] == x ? x : pa[x] = find(pa[x]); } boolunionSet(int x, int y){ x = find(x), y = find(y); if (x == y) returnfalse; if (sz[x] < sz[y]) swap(x, y); pa[y] = x; sz[x] += sz[y]; cnt--; returntrue; } };
classSolution { public: intmaxNumEdgesToRemove(int n, vector<vector<int>>& edges){ vector<vector<pair<int, int>>> lst(3); for (auto& e : edges){ lst[e[0]-1].emplace_back(e[1]-1, e[2]-1); } int ans = 0; DSU uf1(n), uf2(n); for (auto& e : lst[2]){ int u = e.first, v = e.second; if (!uf1.unionSet(u, v) || !uf2.unionSet(u, v)) ans++; } for (auto& e : lst[0]){ int u = e.first, v = e.second; if (!uf1.unionSet(u, v)) ans++; } for (auto& e : lst[1]){ int u = e.first, v = e.second; if (!uf2.unionSet(u, v)) ans++; } return uf1.cnt == 1 && uf2.cnt == 1 ? ans : -1; } };
寫在最後
Cover photo is generated by @たろたろ, thanks for their work!