2646. 最小化旅行的价格总和
题目链接:2646. 最小化旅行的价格总和
方法一:dfs + 树形dp
解题思路
- 先不考虑哪些节点的代价需要减半:
- 由题可知,本题的数据结构是一个图存储的无根树,那么表示从
到 之间只有唯一的一条路线,那么我们对于 中的每个询问,通过 找寻从 到 过程中走过的节点,最终计算出每个节点需要经过的次数,然后乘以对应的 得到当前节点所需要的总代价。
- 由题可知,本题的数据结构是一个图存储的无根树,那么表示从
- 接下来考虑将哪些非相邻节点的价格减半:
- 为了使得最终代价最小,那么应该选择其中所占代价最大的方案,并将其对应的节点价格减半;
- 那么问题就变成了选择非相邻节点构成的集合的最大代价;
- 即典型的树形
问题:- 当前节点由两种选择,
, ,当前节点的值可以由其所有非自身的邻接点转移过来; select = val + sum(next.second)
,当前节点选择后,邻接点不能选择;no_select = sum(max(next.first, next.second))
,当前节点不选择,邻接点可选可不选,取其中最大值;- 返回
; - 递归边界:由于每次都是找的邻接点,当都遍历完时,递归会自动结束。
- 当前节点由两种选择,
代码
class Solution {
public:
int minimumTotalPrice(int n, vector<vector<int>>& edges, vector<int>& price, vector<vector<int>>& trips) {
vector<vector<int>> adj(n);
vector<int> w(n), path;
for (auto &e : edges) {
adj[e[0]].push_back(e[1]);
adj[e[1]].push_back(e[0]);
}
function<void(int, int, int)> dfs1 = [&](int u, int fa, int ed) -> void {
if (u == ed) {
for (auto &v : path) w[v] ++ ;
w[u] ++ ;
return ;
}
path.push_back(u);
for (auto &v : adj[u])
if (v != fa) dfs1(v, u, ed);
path.pop_back();
};
for (int i = 0; i < trips.size(); i ++ ) {
int st = trips[i][0], ed = trips[i][1];
dfs1(st, -1, ed);
}
int sum = 0;
for (int i = 0; i < n; i ++ ) {
w[i] = w[i] * price[i];
sum += w[i];
}
function<pair<int, int>(int, int)> dfs2 = [&](int u, int fa) -> pair<int, int> {
int select = w[u], not_select = 0;
pair<int, int> next;
for (auto &v : adj[u])
if (v != fa) {
next = dfs2(v, u);
select += next.second;
not_select += max(next.first, next.second);
}
return {select, not_select};
};
pair<int, int> ans = dfs2(0, -1);
return sum - max(ans.first, ans.second) / 2;
}
};
复杂度分析
时间复杂度:对于
空间复杂度:
方法二:树上差分 + LCA
待续...
分类:
leetcode题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】