leetcode_1579. 保证图可完全遍历

一、题目内容

Alice 和 Bob 共有一个无向图,其中包含 n 个节点和 3  种类型的边:

  • 类型 1:只能由 Alice 遍历。
  • 类型 2:只能由 Bob 遍历。
  • 类型 3:Alice 和 Bob 都可以遍历。

给你一个数组 edges ,其中 edges[i] = [typei, ui, vi] 表示节点 ui 和 vi 之间存在类型为 typei 的双向边。请你在保证图仍能够被 Alice和 Bob 完全遍历的前提下,找出可以删除的最大边数。如果从任何节点开始,Alice 和 Bob 都可以到达所有其他节点,则认为图是可以完全遍历的。

返回可以删除的最大边数,如果 Alice 和 Bob 无法完全遍历图,则返回 -1 。

示例 1:

输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,3],[1,2,4],[1,1,2],[2,3,4]]
输出:2
解释:如果删除 [1,1,2] 和 [1,1,3] 这两条边,Alice 和 Bob 仍然可以完全遍历这个图。再删除任何其他的边都无法保证图可以完全遍历。所以可以删除的最大边数是 2 。

示例 2:

输入:n = 4, edges = [[3,1,2],[3,2,3],[1,1,4],[2,1,4]]
输出:0
解释:注意,删除任何一条边都会使 Alice 和 Bob 无法完全遍历这个图。

示例 3:

输入:n = 4, edges = [[3,2,3],[1,1,2],[2,3,4]]
输出:-1
解释:在当前图中,Alice 无法从其他节点到达节点 4 。类似地,Bob 也不能达到节点 1 。因此,图无法完全遍历。

提示:

1 <= n <= 10^5
1 <= edges.length <= min(10^5, 3 * n * (n-1) / 2)
edges[i].length == 3
1 <= edges[i][0] <= 3
1 <= edges[i][1] < edges[i][2] <= n
所有元组 (typei, ui, vi) 互不相同

二、解题思路

维护三种线段的连通关系,线段3一般要保留,毕竟是公用的

具体思路看代码注释。

三、代码


  
  1. class Solution:
  2. def maxNumEdgesToRemove(self, n: int, edges: list) -> int:
  3. uf1 = UnionFind(n)
  4. uf2 = UnionFind(n)
  5. uf3 = UnionFind(n)
  6. count1 = 0 # 线段1的个数
  7. count2 = 0 # 线段2的个数
  8. count3 = 0 # 线段3的个数
  9. redundant_count3 = 0 # 线段3冗余的个数
  10. for i in range(len(edges)):
  11. edge_type = edges[i][0] # 线段种类
  12. st = edges[i][1] - 1
  13. ed = edges[i][2] - 1
  14. # 记录每种线段的个数
  15. if edge_type == 1:
  16. count1 += 1
  17. elif edge_type == 2:
  18. count2 += 1
  19. elif edge_type == 3:
  20. count3 += 1
  21. else:
  22. raise ValueError
  23. # 每种线段进行连通
  24. if edge_type == 1 or edge_type == 3:
  25. uf1.Union(st, ed)
  26. if edge_type == 2 or edge_type == 3:
  27. uf2.Union(st, ed)
  28. if edge_type == 3:
  29. if not uf3.isConnected(st, ed):
  30. uf3.Union(st, ed)
  31. else:
  32. # 已经连通说明冗余
  33. redundant_count3 += 1
  34. # 线段3直接连通了所有点
  35. if uf3.getCount() == 1:
  36. return count1 + count2 + redundant_count3 # 删除的边可以是线段1+线段2+线段3冗余的个数
  37. # 线段1和线段2同时连通, 那么都可以走的路不需要删除,也就是线段3不需要删除,但是要删除线段3的冗余
  38. if uf1.getCount() == 1 and uf2.getCount() == 1:
  39. return count1 - (uf3.getCount() - 1) + \
  40. count2 - (uf3.getCount() - 1) + redundant_count3
  41. return -1
  42. class UnionFind:
  43. def __init__(self, n):
  44. self.count = n
  45. self.root = [0 for _ in range(n)]
  46. self.size = [0 for _ in range(n)]
  47. for i in range(n):
  48. self.root[i] = i
  49. self.size[i] = i
  50. def find(self, x):
  51. if x != self.root[x]:
  52. self.root[x] = self.find(self.root[x])
  53. return self.root[x]
  54. else:
  55. return x
  56. def isConnected(self, x, y):
  57. return self.find(x) == self.find(y)
  58. def getCount(self):
  59. return self.count
  60. def Union(self, x, y):
  61. # 查找x和y的根/父节点
  62. rx = self.find(x)
  63. ry = self.find(y)
  64. # 根/父节点相同, 说明已经连通了
  65. if rx == ry:
  66. return # 直接返回
  67. if self.size[rx] < self.size[ry]:
  68. self.root[rx] = ry
  69. self.size[ry] += self.size[rx]
  70. else:
  71. self.root[ry] = rx
  72. self.size[rx] += self.size[ry]
  73. self.count -= 1
  74. if __name__ == '__main__':
  75. s = Solution()
  76. n = 4
  77. edges = [[3, 1, 2],
  78. [3, 2, 3],
  79. [1, 1, 3],
  80. [1, 2, 4],
  81. [1, 1, 2],
  82. [2, 3, 4]]
  83. ans = s.maxNumEdgesToRemove(n, edges)
  84. print(ans)

文章来源: nickhuang1996.blog.csdn.net,作者:悲恋花丶无心之人,版权归原作者所有,如需转载,请联系作者。

原文链接:nickhuang1996.blog.csdn.net/article/details/113242638

(完)