本次题目都来自卡码网
108. 冗余连接
无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)。
- 从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
- 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
class UnionFind:def __init__(self, n):self.n = nself.father = [0] * (n + 1)for i in range(n + 1):self.father[i] = idef find(self, u):if u == self.father[u]:return uelse:self.father[u] = self.find(self.father[u])return self.father[u]def join(self, u, v):u = self.find(u)v = self.find(v)if u == v:returnelse:self.father[u] = vdef is_same(self, u, v):u = self.find(u)v = self.find(v)return u == vif __name__ == '__main__':n = int(input())UnionFind = UnionFind(n)for i in range(n):s, t = map(int, input().strip().split())if UnionFind.is_same(s, t):print(str(s) + " " + str(t))exit()else:UnionFind.join(s, t)
109. 冗余连接II
1、先考虑节点有两个入度的情况,其中必定有一个是冗余的
2、如果不存在1的情况,则考虑环的情况
class UnionFind:def __init__(self, n):self.n = nself.father = [0] * (n + 1)for i in range(n + 1):self.father[i] = idef find(self, u):if u == self.father[u]:return uelse:self.father[u] = self.find(self.father[u])return self.father[u]def join(self, u, v):u = self.find(u)v = self.find(v)if u == v:returnelse:self.father[u] = vdef is_same(self, u, v):u = self.find(u)v = self.find(v)return u == v# 在有向图里找到删除的那条边,使其变成树
def getRemoveEdge(edges, n):union_find = UnionFind(n) # 初始化并查集for i in range(union_find.n): # 遍历所有的边if union_find.is_same(edges[i][0], edges[i][1]): # 构成有向环了,就是要删除的边print(str(edges[i][0]) + " " + str(edges[i][1]))else:union_find.join(edges[i][0], edges[i][1])# 删一条边之后判断是不是树
def isTreeAfterRemoveEdge(edges, deleteEdge, n):union_find = UnionFind(n) # 初始化并查集for i in range(union_find.n):if i == deleteEdge:continueif union_find.is_same(edges[i][0], edges[i][1]): # 构成有向环了,一定不是树return Falseelse:union_find.join(edges[i][0], edges[i][1])return Trueif __name__ == '__main__':n = int(input())edges = []inDegree = [0] * (n + 1) # 记录节点入度for i in range(n):s, t = map(int, input().strip().split())inDegree[t] += 1edges.append((s, t))inDegree2 = [] # 记录入度为2的边(如果有的话就两条边)# 找入度为2的节点所对应的边,注意要倒序,因为优先删除最后出现的一条边for i in range(n - 1, -1, -1):if inDegree[edges[i][1]] == 2:inDegree2.append(i)if len(inDegree2) > 0:# 放在inDegree2里的边已经按照倒叙放的,所以这里就优先删inDegree2[0]这条边if isTreeAfterRemoveEdge(edges, inDegree2[0], n):print(str(edges[inDegree2[0]][0]) + " " + str(edges[inDegree2[0]][1]))else:print(str(edges[inDegree2[1]][0]) + " " + str(edges[inDegree2[1]][1]))exit()# 处理情况三# 明确没有入度为2的情况,那么一定有有向环,找到构成环的边返回就可以了getRemoveEdge(edges, n)