本次题目都来自卡码网
108. 冗余连接
无向图,返回一条可以删去的边,使得结果图是一个有着N个节点的树(即:只有一个根节点)。
- 从前向后遍历每一条边(因为优先让前面的边连上),边的两个节点如果不在同一个集合,就加入集合(即:同一个根节点)。
- 如果边的两个节点已经出现在同一个集合里,说明着边的两个节点已经连在一起了,再加入这条边一定就出现环了。
python
class UnionFind:
def __init__(self, n):
self.n = n
self.father = [0] * (n + 1)
for i in range(n + 1):
self.father[i] = i
def find(self, u):
if u == self.father[u]:
return u
else:
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:
return
else:
self.father[u] = v
def is_same(self, u, v):
u = self.find(u)
v = self.find(v)
return u == v
if __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的情况,则考虑环的情况
python
class UnionFind:
def __init__(self, n):
self.n = n
self.father = [0] * (n + 1)
for i in range(n + 1):
self.father[i] = i
def find(self, u):
if u == self.father[u]:
return u
else:
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:
return
else:
self.father[u] = v
def 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:
continue
if union_find.is_same(edges[i][0], edges[i][1]): # 构成有向环了,一定不是树
return False
else:
union_find.join(edges[i][0], edges[i][1])
return True
if __name__ == '__main__':
n = int(input())
edges = []
inDegree = [0] * (n + 1) # 记录节点入度
for i in range(n):
s, t = map(int, input().strip().split())
inDegree[t] += 1
edges.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)