代码随想录算法训练营第六十天| 图论7—卡码网53. 寻宝

图论第七天,prim和kruskal算法,说实话都没看的很懂,有点抽象难理解,只能照着题解理解一下了。

53. 寻宝(prim)

53. 寻宝(第七期模拟笔试)

复制一下网站上的prim算法的结论

prim算法三部曲

  1. 第一步,选距离生成树最近节点
  2. 第二步,最近节点加入生成树
  3. 第三步,更新非生成树节点到生成树的距离(即更新minDist数组)

minDist数组是prim算法的灵魂,它帮助prim算法完成最重要的一步,就是如何找到距离最小生成树最近的点 。再来帮大家回顾minDist数组的含义:记录每一个节点距离最小生成树的最近距离。我们根据minDist数组,选取距离生成树最近的节点加入生成树,那么minDist数组里记录的其实也是最小生成树的边的权值

节点数v和边数e,不可达的点对初始化为10001。读取边信息,更新邻接矩阵,表示每对相连节点之间的权重。定义两个辅助数组,visited用于标记哪些节点已加入最小生成树,minDist用于记录每个节点到当前生成树的最短距离。主循环执行v次,每次选出未加入树的、距离当前生成树最近的节点,并更新其他节点的minDist值。最后,累加这些最短边的权重得到最小生成树的权重值并输出。

python 复制代码
# 接收输入
v, e = list(map(int, input().strip().split()))
# 按照常规的邻接矩阵存储图信息,不可达的初始化为10001
graph = [[10001] * (v+1) for _ in range(v+1)]
for _ in range(e):
    x, y, w = list(map(int, input().strip().split()))
    graph[x][y] = w
    graph[y][x] = w

# 定义加入生成树的标记数组和未加入生成树的最近距离
visited = [False] * (v + 1)
minDist = [10001] * (v + 1)

# 循环 n - 1 次,建立 n - 1 条边
# 从节点视角来看:每次选中一个节点加入树,更新剩余的节点到树的最短距离,
# 这一步其实蕴含了确定下一条选取的边,计入总路程 ans 的计算
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] > graph[cur][j]:
            minDist[j] = graph[cur][j]

ans = 0
for i in range(2, v + 1):
    ans += minDist[i]
print(ans)

53. 寻宝(kruskal)

prim 算法是维护节点的集合,而 Kruskal 是维护边的集合

kruscal的思路:

  • 边的权值排序,因为要优先选最小的边加入到生成树里
  • 遍历排序后的边
    • 如果边首尾的两个节点在同一个集合,说明如果连上这条边图中会出现环
    • 如果边首尾的两个节点不在同一个集合,加入到最小生成树,并把两个节点加入同一个集合

不同的点是在重点维护边,所以定义边的类edge存储每条边的两个端点和权重,初始化father并查集数组判断是不是环。节点数v和边数e与prim算法中是一样的,并将所有边读入一个列表中。随后进入Kruskal 函数,先按边权从小到大排序,然后遍历所有边,检查该边的两个端点是否已属于同一个集合,若不在同一集合中则将其合并并将该边的权重加入最终结果中。这个过程直到所有节点连通为止。

python 复制代码
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__":
    import sys
    input = sys.stdin.read
    data = input().split()

    v = int(data[0])
    e = int(data[1])

    edges = []
    index = 2
    for _ in range(e):
        v1 = int(data[index])
        v2 = int(data[index + 1])
        val = int(data[index + 2])
        edges.append(Edge(v1, v2, val))
        index += 3

    result_val = kruskal(v, edges)
    print(result_val)
相关推荐
C++ 老炮儿的技术栈27 分钟前
C++中什么是函数指针?
c语言·c++·笔记·学习·算法
大耳猫1 小时前
卡尔曼滤波算法简介与 Kotlin 实现
算法·kotlin·卡尔曼滤波
重生之后端学习1 小时前
day23-集合(泛型&Set&数据结构)
java·开发语言·数据结构·算法
冲帕Chompa1 小时前
代码随想录图论part4
图论
焜昱错眩..2 小时前
代码随想录训练营第二十一天 |589.N叉数的前序遍历 590.N叉树的后序遍历
数据结构·算法
Tisfy3 小时前
LeetCode 1550.存在连续三个奇数的数组:遍历
算法·leetcode·题解·数组·遍历
wang__123003 小时前
力扣70题解
算法·leetcode·职场和发展
菜鸟破茧计划3 小时前
滑动窗口:穿越数据的时光机
java·数据结构·算法
_Itachi__4 小时前
LeetCode 热题 100 101. 对称二叉树
算法·leetcode·职场和发展
少了一只鹅4 小时前
深入理解指针(5)
java·c语言·数据结构·算法