学习资料:https://www.programmercarl.com/kamacoder/0108.冗余连接.html#思路
图论
并查集
prim算法
kruskal算法
学习记录:
108.冗余连接
点击查看代码
# 并查集解法
class UnionFind:
def __init__(self, size):
self.parent = list(range(size+1))
def find(self, u):
if u == self.parent[u]:
return u
else:
self.parent[u] = self.find(self.parent[u])
return self.parent[u]
def join(self, u, v):
"""将v->u这条边加入并查集"""
u = self.find(u)
v = self.find(v)
if u != v:
self.parent[v] = u
def isSame(self, u, v):
u = self.find(u)
v = self.find(v)
return u == v
# 实时更新冗余边,如果有多条,那就保留最后一个,也就是最新款
result = None
# 输入值
n = int(input())
# 调用类
uf = UnionFind(n)
# 继续输入剩余信息
for i in range(n):
s, t = map(int, input().split())
# 判断s和t是否同根
if uf.isSame(s, t):
result = str(s) + ' ' + str(t)+'\t'
else:
uf.join(s, t)
# 输出多余边的结果
print(result)
109.冗余连接2(三种情况;关注入度为2的节点)
点击查看代码
class UnionFind():
def __init__(self, size):
self.parent = list(range(size + 1))
def find(self, u):
if u == self.parent[u]:
return u
self.parent[u] = self.find(self.parent[u])
return self.parent[u]
def join(self, u, v):
u = self.find(u)
v = self.find(v)
if u != v:
self.parent[u] = v
def isSame(self, u, v):
return self.find(u) == self.find(v)
def is_tree_after_remove_edge(self, edges, edge, n):
# 创建一个新的 UnionFind 实例以避免状态污染
temp_uf = UnionFind(n)
for i in range(len(edges)):
if i == edge:
continue
s, t = edges[i]
if temp_uf.isSame(s, t):
return False # 存在环
temp_uf.join(s, t)
return True
def get_remove_edge(self, edges):
for s, t in edges:
if self.isSame(s, t):
print(s, t)
return
else:
self.join(s, t)
# 输入值
n = int(input())
uf = UnionFind(n)
edges = []
indegree = {}
# 输入边的信息并统计入度
for _ in range(n):
s, t = map(int, input().split())
indegree[t] = indegree.get(t, 0) + 1
edges.append([s, t])
# 找入度为2的节点,记录下标
vec = []
for i in range(n - 1, -1, -1):
if indegree[edges[i][1]] == 2:
vec.append(i)
# 输出结果
if len(vec) > 0:
# 情况一:删除靠后的边
if uf.is_tree_after_remove_edge(edges, vec[0], n):
print(edges[vec[0]][0], edges[vec[0]][1])
# 情况二:只能删除特定的边
else:
print(edges[vec[1]][0], edges[vec[1]][1])
else:
# 情况三:原图有环
uf.get_remove_edge(edges)
53.寻宝(两种方法)
点击查看代码
# kruskal算法:关注边的算法。找到最短的边,如果对应的这条边的两个节点不在同一个集合,就把边加入生成树,把两个节点加入同一个集合
class Edge:
def __init__(self, l, r, val):
# 边的左节点和右节点和权值
self.l = l
self.r = r
self.val = val
n = 10001
father = list(range(n))
def init():
global father
father = list(range(n))
def find(u):
if u!=father[u]:
father[u] = find(father[u])
return father[u]
def join(u, v):
u = find(u)
v = find(v)
if u!=v:
father[v] = u
def kruskal(v, edges):
edges.sort(key=lambda edge: edge.val)
init()
result_val = 0
for edge in edges:
x = find(edge.l)
y = find(edge.r)
if x!=y:
result_val += edge.val
join(x, y)
return result_val
if __name__ == "__main__":
# 输入值
v, e = map(int, input().split())
edges = []
for _ in range(e):
v1, v2, val = map(int, input().split())
edges.append(Edge(v1, v2, val))
result_val = kruskal(v, edges)
print(result_val)
# # grim法:关注节点。三大步,选中距离生成树最近的节点;将该节点加入生成树;更新其余非生成树节点到生成树的最小距离
# # 输入值
# v, e = map(int, input().split())
# # 把剩余地图信息加入邻接矩阵,每个节点都初始化为10001,输入值用于存储两边的权值
# grid = [[10001] *(v+1) for _ in range(v+1)]
# for _ in range(e):
# x, y, w = map(int, input().split())
# # 点1到点2和点2到点1的距离一样,双向
# grid[x][y] = w
# grid[y][x] = w
# # 定义一个数组,用于保存该节点是否加入生成树中
# visited = [False]*(v+1)
# # 定义一个数组用于记录每个点距离生成树的最近距离,初始设置为10001
# minDist = [10001] * (v+1)
# # 按题目要求n个点,只需要n-1条边
# for _ in range(1, v+1):
# min_val = 10002
# cur = -1
# for j in range(1, v+1):
# if visited[j]==False and minDist[j] < min_val:
# cur = j
# min_val = minDist[j]
# visited[cur] = True
# for j in range(1, v+1):
# if visited[j]==False and minDist[j]>grid[cur][j]:
# minDist[j]=grid[cur][j]
# ans = 0
# for i in range(2, v+1):
# ans += minDist[i]
# print(ans)
PS:今天好冷,阴转多云。拖了两天的内容,赶紧补上,好累,根本看不懂,不想看,都是抄的,下次回来再学
周末吃了黄焖鸡、圆子汤,今天吃了羊肉汤。
好不爽好烦!!!!平等的讨厌每个人!!!!第一次这么讨厌周日!!!! 烦死了
其实还是很伤心,怀念哥哥的一天
倒计时一周