代码随想录算法营Day62 | 寻宝(Prim算法,kruskal算法)

寻宝(Prim算法,kruskal算法)

在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。

不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通起来(注意:这是一个无向图)。 

给定一张地图,其中包括了所有的岛屿,以及它们之间的距离。以最小化公路建设长度,确保可以链接到所有岛屿。

最小生成树Prim算法

需要一个minDist数组记录每个节点到最小生成树的最近距离。这个算法分三步走。

1.选取离最小生成树最近的节点

2.将最近的节点加入生成树

3.更新其他未加入节点到最小生成树的距离


v,e = map(int,input().split())
grid = [[10001] * (v + 1) for _ in range(v + 1)]
for _ in range(e):
    x,y,val = map(int,input().split())
    grid[x][y] = val
    grid[y][x] = val

isInTree = [False] * (v+1)
minDist = [10001] * (v+1)

for i in range(1,v):
    cur = -1
    minVal = 10002
    #1.选取离最小生成树最近的节点
    for j in range(1,v+1):
        if not isInTree[j] and minDist[j] < minVal:
            cur = j
            minVal = minDist[j]
    #2.将最近的节点加入生成树
    isInTree[cur] = True
    #3.更新其他未加入节点到最小生成树的距离
    for j in range(1,v+1):
        if not isInTree[j] and grid[cur][j] < minDist[j]:
            minDist[j] = grid[cur][j]
print(sum(minDist[2:]))

最小生成树Krusal算法

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

kruscal的思路:

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

class Edge:
    def __init__(self,x,y,val):
        self.x = x
        self.y = y
        self.val = val

v,e = map(int,input().split())
father = list(range(v+1))
edges = []

for _ in range(e):
    x,y,val = map(int,input().split())
    edges.append(Edge(x,y,val))

def init():
    global father
    father = list(range(v+1))

def find(u):
    if father[u] == u:
        return u
    else:
        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 krusal(edges):
    edges.sort(key=lambda x:x.val)
    init()
    result = 0
    for edge in edges:
        x = find(edge.x)
        y = find(edge.y)
        if x != y:
            join(x,y)
            result += edge.val
    return result

res = krusal(edges)
print(res)


你可能感兴趣的:(算法,python)