1 条题解
-
0
问题分析
本题是一道基于树结构和贪心算法的路径优化问题,核心任务是在一棵树上找到最多的节点,使得从两个指定起点(
X和Y)到达这些节点的路径总代价不超过给定阈值K。算法需要结合深度优先搜索(DFS)、优先队列和贪心策略,高效计算符合条件的最大节点数量。算法思路
1. 树结构与距离计算
- 树的表示:使用邻接表存储树的边,
fr、ne、v、w数组共同构成邻接表,其中w存储边的权重。 - 距离计算:通过两次DFS分别计算从起点
X到所有节点的距离da[],以及从起点Y到所有节点的距离db[]:dfs0(X, 0, 0, da):以X为根,计算每个节点到X的距离并存储在da中。dfs0(Y, 0, 0, db):以Y为根,计算每个节点到Y的距离并存储在db中。
2. 初始贪心策略(
count0函数)- 核心思想:使用优先队列(最小堆)模拟从
X和Y同时扩展节点的过程,每次选择代价最小的路径扩展,直到总代价超过K。 - 优先级队列:存储
(当前总代价, 节点),其中节点为正表示从X扩展,为负表示从Y扩展。 - 扩展规则:每次弹出代价最小的节点,累加计数,并将其未访问的邻接节点按新代价(从
X或Y到该邻接节点的距离)加入队列。 - 终止条件:队列顶部节点的代价超过剩余
K时停止,返回累计的节点数量。
3. 优化贪心策略(
cal函数)- 节点分类:将节点分为两类:
- 一类是
2*a < b(a为da[i],b为db[i],已交换确保a ≤ b),直接拆分路径代价为a和b-a。 - 另一类是
2*a ≥ b,保留为(a, b)结构,用于后续组合优化。
- 一类是
- 排序与前缀和:
- 对拆分后的代价数组
v2排序,对保留的(a, b)按b排序,并计算前缀和su。 - 预计算最优组合的最小代价
h1,用于快速查询不同数量节点的最小总代价。
- 对拆分后的代价数组
- 组合优化:通过双指针遍历,找到拆分代价与保留代价的最优组合,使得总代价不超过
K且节点数量最多。
4. 结果融合
- 比较初始贪心策略(
count0)和优化贪心策略(cal)的结果,取最大值作为最终答案。
关键公式与复杂度
-
距离计算:
- 节点
i到X的距离:da[i] = da[父节点] + 边权重 - 节点
i到Y的距离:db[i] = db[父节点] + 边权重时间复杂度:O(N)(两次DFS遍历树)。
- 节点
-
初始贪心扩展:
- 每个节点最多入队一次,优先队列操作时间复杂度为
O(N log N)。
- 每个节点最多入队一次,优先队列操作时间复杂度为
-
优化贪心策略:
- 排序操作:
O(N log N)(对拆分代价和保留代价排序)。 - 双指针组合查询:
O(N)。 总时间复杂度:O(N log N)。
- 排序操作:
-
整体复杂度:
O(N log N),其中N为树的节点数量,适合处理N ≤ 2×10^5的规模。
代码解析
模块 功能描述 树的构建 addb函数构建邻接表,存储树的边和权重。距离计算 dfs0函数通过DFS计算节点到起点的距离。初始贪心 count0函数使用优先队列扩展节点,计算最大数量。优化贪心 cal函数通过分类、排序和组合优化,计算更优解。主函数 整合所有步骤,返回两种策略中的最大值作为答案。 算法的核心是结合两种贪心策略:初始策略通过优先队列模拟扩展过程,优化策略通过分类和组合进一步挖掘最优解,最终在保证效率的前提下得到最大节点数量。
- 树的表示:使用邻接表存储树的边,
- 1
信息
- ID
- 3291
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 15
- 已通过
- 1
- 上传者