题解 | #送快递#
先找到最长的路径,得到路径的长度depth。那么剩下的节点还能访问的数量则要根据剩余电量来判断。
想要求出快递员最多可以送多少个用户,则需要规划出一条路径做到用最少的电量访问更多的用户。可以抽象理解为,用最短的路径访问图中最多的节点。
那么,思考一个简化的问题:
(1)从当前节点0开始做深度优先遍历,找到最长的路径称为主干path,长度为depth。从0出发,沿着path依次遍历。
(2)每次遇到一个分支就进入访问该分支的节点,访问完成后原路返回到主干path。这个过程走过的路径长度为2d,d为分支上的节点数。
(3)返回主干path后,继续向下遍历。遇到分支就回到第二步。
当走完所有节点后,对于主干path上的路径我们只走了一遍,所有分支上的路径都走了两遍。因此,遍历所有节点的最短路径为:depth+2D,depth为最长的路径主干path的长度,D为分支路径的长度。
回到送快递问题,快递员在0号位置出发,首先需要找到最长的路径path,长度为depth,然后判断剩余电量K是否大于depth。
若k<=depth,则返回1+k。这种情况沿着最长路径送快递就行。
若k>depth,则返回1+depth+(k-depth)//2。这种情况不仅需要沿着最长路径送快递,且遇到分支也需要送快递。(k-depth)为在保证快递员送完主干路径上的用户后还剩余的电量,这些电量用来为分支路径上的用户送快递。因为,送完分支上的用户还需返回,因此能送的分支用户数计算为(k-depth)//2。
def dfs(maps,cur, visited,path,max_depth): if len(path) > max_depth[0]: max_depth[0]=len(path) for neibor in maps[cur]: if visited[neibor]: pass else: visited[neibor] = True path.append(neibor) dfs(maps,neibor, visited,path,max_depth) path.pop() visited[neibor] = False if __name__ == "__main__": line1 = list(map(int, input().split())) n, k = line1[0], line1[1] S = list(map(int, input().split())) # S # 邻接表 maps = [[] for i in range(n)] for i in range(n - 1): # (i+1) <----------> S[i] if S[i] in maps[i + 1]: pass else: maps[i + 1].append(S[i]) if (i + 1) in maps[S[i]]: pass else: maps[S[i]].append(i + 1) # print(maps) visited = [False]*n visited[0]=True# 0节点已经访问 path = [0] max_depth = [1] # print(distance[0]) dfs(maps,0, visited,path,max_depth) max_depth = max_depth[0]-1 # print(path) if k <=max_depth: print(k+1) else: print(min(n,max_depth +1+ (k-max_depth)//2))