蓝桥 1024 第 2 场算法双周赛 串门【算法赛】python解析

蓝桥 1024 第 2 场算法双周赛 串门【算法赛】

时间:2023.10.30
题目地址:串门【算法赛】

题目分析

题目说这个输入数据保证是树,那就可以不用想太多了。找到最小路径,还要保证每个门都串到,那么必定会有一段路是走了两遍的,一来一回。推导如下:
那就要让这走了两遍的路程最小 => 从起点到终点的走了一遍的距离最大 => 将所有路径和的两倍 - 从起点到终点的走了一遍的距离最大 => 树的所有边之和*2 - 树的直径
① 树的所有边之和简单,读数据的时候可以直接得到。
② 目标就是树的直径,所以这个题目就转化成求树的直径了。可以参考树的直径
然后方法便是两次dfs/bfs,第一次随便从一个点出发找到树直径的一个端点,第二次从这个端点出发,找到另一个端点,直径就出来了。

代码

① 不能通过的深搜算法(家人们感觉不知道为什么通过不了,时间超了,感觉跟下面的bfs差不多啊)

def dfs(net, fa, d): # fa是父节点,防止回溯; d是存走到当前点的长度
    for nnet, m in relation[net]:
        if nnet == fa or d[nnet] != -1:   # 掉头,走过了
            continue
        d[nnet] = d[net] + m
        dfs(nnet, net, d)
    target = d.index(max(d))
    return target, d

n = int(input())
relation = [[] for _ in range(n+1)]
res = 0
for i in range(n-1):
    u, v, m = map(int, input().split())
    res = res + 2*m
    relation[u].append((v, m))
    relation[v].append((u, m))

d = [-1 for _ in range(n+1)]
d[1] = 0
t_t, _ = dfs(1, 0, d)
d = [-1 for _ in range(n+1)]
d[t_t] = 0
target, d = dfs(t_t, 0, d)
res -= d[target]
print(res)

② AC代码,bfs。

from collections import deque

def bfs(net):
    d = [-1 for _ in range(n+1)]
    d[net] = 0
    q = deque([net])
    while q:
        nn = q.popleft()
        for nnet, m in relation[nn]:
            if d[nnet] != -1: # 掉头
                continue
            d[nnet] = d[nn] + m
            q.append(nnet)
    target = d.index(max(d))
    return target, d

n = int(input())
relation = [[] for _ in range(n+1)]
res = 0
for i in range(n-1):
    u, v, m = map(int, input().split())
    res = res + 2*m
    relation[u].append((v, m))
    relation[v].append((u, m))

t_t, _ = dfs(1)
target, d = dfs(t_t)
res -= d[target]
print(res)

总结

有人知道为什么第二个代码比第一个代码快?,感觉实现的差不多啊。

你可能感兴趣的:(#,算法学习的小记录,算法,python,图论)