目录
- 并查集理论基础
- 思路
- 任务
- 1971. 寻找图中是否存在路径
- 思路一
- 思路二
- 1971. 寻找图中是否存在路径
并查集理论基础
思路
用一维数组来维护这样的结构,数组的索引表示某个值,数组的值表示该索引同一集合的根
# n 根据题目中的节点数量而定,一般比节点数量大一点就好
n = 1005
father = [0] * n # Python 中列表的初始大小为 n,并用 0 填充# 并查集初始化
def init():for i in range(n):father[i] = i# 并查集里寻根的过程
def find(u):if u == father[u]:return uelse:father[u] = find(father[u]) # 路径压缩return father[u]# 判断 u 和 v 是否找到同一个根
def is_same(u, v):u = find(u)v = find(v)return u == v# 将 v->u 这条边加入并查集
def join(u, v):u = find(u) # 寻找 u 的根v = find(v) # 寻找 v 的根if u == v:return # 如果发现根相同,说明在一个集合,不用两个节点相连,直接返回father[v] = u
任务
1971. 寻找图中是否存在路径
有一个具有 n 个顶点的 双向 图,其中每个顶点标记从 0 到 n - 1(包含 0 和 n - 1)。图中的边用一个二维整数数组 edges 表示,其中 edges[i] = [ui, vi] 表示顶点 ui 和顶点 vi 之间的双向边。 每个顶点对由 最多一条 边连接,并且没有顶点存在与自身相连的边。
请你确定是否存在从顶点 source 开始,到顶点 destination 结束的 有效路径 。
给你数组 edges 和整数 n、source 和 destination,如果从 source 到 destination 存在 有效路径 ,则返回 true,否则返回 false 。
思路一
第一个想到的是dfs(之前解过求两个点之间的所有路径),由于是找是否存在,所以是有返回值的dfs,此时考虑类树形DP,下层告诉上层是否找到路径。
class Solution:def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool:# 将边集转化为邻接表graph = defaultdict(list)for a,b in edges:graph[a].append(b)graph[b].append(a)visited = [False] * nreturn self.dfs(graph,source,destination,visited)# 有返回值的dfs,有点类似于树形DPdef dfs(self,graph,start,end,visited):visited[start] = Trueif start == end: #终止条件在终点return Truefor i in graph[start]:if not visited[i]:if self.dfs(graph,i,end,visited): #如果下层返回True,则本层向上返回True,表示找到到达终点的路径return Truereturn False
思路二
本章所学的并查集正好对应这道题,只要在一条边上,就归为同一集合,连续的边的连接归为同一集合(该集合内的点都能到达),最后判断source和des是否为同一集合即可。
class Solution:def validPath(self, n: int, edges: List[List[int]], source: int, destination: int) -> bool:unionFind = UnionFind(n)for i in range(len(edges)):unionFind.join(edges[i][0],edges[i][1])return unionFind.is_same(source,destination)class UnionFind:def __init__(self,n):self.father = [0] * nfor i in range(n):self.father[i] = i# (查) def find(self,u): if u == self.father[u]:return uelse:self.father[u] = self.find(self.father[u]) # 路径压缩(一直像上层返回最底层的值,并且一直赋值)return self.father[u]# 判断 u 和 v 是否找到同一个根def is_same(self,u, v): u = self.find(u)v = self.find(v)return u == v# 将 v->u 这条边加入并查集 (并)def join(self,u, v):u = self.find(u) # 寻找 u 的根v = self.find(v) # 寻找 v 的根if u == v:return # 如果发现根相同,说明在一个集合,不用两个节点相连,直接返回self.father[v] = u #否则其中一根归于另一根