时间: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)
有人知道为什么第二个代码比第一个代码快?,感觉实现的差不多啊。