算法工程师第四十九天(寻宝)

参考文献 代码随想录

一、寻宝

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

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

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

输入描述

第一行包含两个整数V 和 E,V代表顶点数,E代表边数 。顶点编号是从1到V。例如:V=2,一个有两个顶点,分别是1和2。

接下来共有 E 行,每行三个整数 v1,v2 和 val,v1 和 v2 为边的起点和终点,val代表边的权值。

输出描述

输出联通所有岛屿的最小路径总距离

输入示例
7 11
1 2 1
1 3 1
1 5 2
2 6 1
2 4 2
2 3 2
3 4 1
4 5 1
5 6 2
5 7 1
6 7 1
输出示例
6
提示信息

数据范围:
2 <= V <= 10000;
1 <= E <= 100000;
0 <= val <= 10000;

如下图,可见将所有的顶点都访问一遍,总距离最低是6.

  

kruskal

(蕴含并查集) 加入到树的时候,从边权小的开始加入,然后如果不在同一个集合里,那么就统计结果,关键在于使用并查集来维护顶点之间的连通性,以此保证最终形成的是一棵包含所有顶点的树

v, e = map(int, input().split())
graph = []
for i in range(e):
    v1, v2, val = map(int, input().split())
    graph.append((v1, v2, val))

graph.sort(key = lambda x: x[2])  # printj就是按边权降序
parent = [i for i in range(v + 1)]  # 初始化每个节点的父亲节点都是自己

def find(x):
    if x != parent[x]:
        parent[x] = find(parent[x])
    return  parent[x]
    
def join(i, j): # 判断2个是否存在一个集合,如果存在
    parent[find(j)] = parent[find(i)]
    
res = 0  
for g1, g2, wt in graph:
    g1 = find(g1)
    g2 = find(g2)
    if g1 != g2:  # 不能构成环
        res += wt
        join(g1, g2)
print(res)

print:每次利用没有遍历过的最小边权去更新其它节点

Dijkstra 算法是求连通图中起始点每一个点之间的最短路径,而prim算法是求连通图的最小生成树,也就是生成树的最短路径之和

v, e = map(int, input().split())
grid = [[10001] * (v + 1) for _ in range(v + 1)]
for i in range(e):
    x, y, w = map(int, input().split())
    grid[x][y] = w
    grid[y][x] = w
    
visied = [False] * (v + 1) # 标记哪些
midist = [10001] * (v + 1)  # 记录最小的距离

for i in range(1, v + 1):
    cur = -1
    mid_val = 10002
    for j in range(1, v + 1):  # 找到一个最小值
        if not visied[j] and midist[j] < mid_val:
            cur = j
            mid_val = midist[j]
    visied[cur] = True
    for j in range(1, v + 1):  # 然后利用当前这个最小值去更新其它点
        if not visied[j] and midist[j] > grid[cur][j]:
            midist[j] = grid[cur][j]
ans = 0
for i in range(2, v + 1):
    ans += midist[i]
print(ans)
            
                    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值