原题地址(困难)

方法1—并查集

思路

见官方题解:

代码

size数组作用是保证两个连通子图相连时,每次都是把小的图连到大的图上,而不是把大的图连到小的图上,所以说其实不加size也没啥问题。

  1. // 并查集模板
  2. class UnionFind {
  3. public:
  4. vector<int> parent;
  5. vector<int> size;
  6. int n;
  7. // 当前连通分量数目
  8. int setCount;
  9. public:
  10. UnionFind(int _n): n(_n), setCount(_n), parent(_n), size(_n, 1) {
  11. iota(parent.begin(), parent.end(), 0); //给parent赋值为0
  12. }
  13. int findset(int x) { // 寻找根
  14. return parent[x] == x ? x : parent[x] = findset(parent[x]);
  15. }
  16. bool unite(int x, int y) {
  17. x = findset(x);
  18. y = findset(y);
  19. if (x == y) {
  20. return false;
  21. }
  22. if (size[x] < size[y]) {
  23. swap(x, y);
  24. }
  25. parent[y] = x;
  26. size[x] += size[y];
  27. --setCount;
  28. return true;
  29. }
  30. };
  31. class Solution {
  32. public:
  33. int maxNumEdgesToRemove(int n, vector<vector<int>>& edges) {
  34. UnionFind ufa(n), ufb(n);
  35. int ans = 0;
  36. // 节点编号改为从 0 开始
  37. for (auto& edge: edges) {
  38. --edge[1];
  39. --edge[2];
  40. }
  41. // 公共边
  42. for (const auto& edge: edges) {
  43. if (edge[0] == 3) {
  44. if (!ufa.unite(edge[1], edge[2])) ++ans;
  45. else ufb.unite(edge[1], edge[2]);
  46. }
  47. }
  48. // 独占边
  49. for (const auto& edge: edges) {
  50. if (edge[0] == 1) {
  51. // Alice 独占边
  52. if (!ufa.unite(edge[1], edge[2])) {
  53. ++ans;
  54. }
  55. }
  56. else if (edge[0] == 2) {
  57. // Bob 独占边
  58. if (!ufb.unite(edge[1], edge[2])) {
  59. ++ans;
  60. }
  61. }
  62. }
  63. if (ufa.setCount != 1 || ufb.setCount != 1) {
  64. return -1;
  65. }
  66. return ans;
  67. }
  68. };