2646. 最小化旅行的价格总和(树的最大独立集)

最大独立集:需要从图中选择尽量多的点,使得这些点互不相邻。
其变形:最大化点权之和。

这道题是一般树的最大独立集
(附:二叉树的最大独立集

另外,树和子树的关系类似原问题和子问题的关系,天然具有递归的特点,这是树形DP的出发点。
思考方向:1)选or不选;2)枚举选哪个

另外,对于数组递归的逻辑是从左到右,对于树递归的逻辑是从叶子到根节点,先解决左右子树。

这道题的思路是暴力dfs每条路径。
对于固定的trips,每个节点经过的次数cnt是不变的,于是首先计算图上所有节点经过的次数cnt
使用dfs计算cnt
然后,我们随便选一个节点出发 DFS,分类讨论:
对于一个节点x和其孩子y,存在两种情况:
1)x的价格减一半,则其孩子y的价格都不能变
2)x的价格不变,则其孩子y的价格可以减一半或者不变,选择其中最小值
于是节点x可以返回的值有两种情况:
1)价格减半时子树x的最小值总和
2)价格不变时子树x的最小值总和
取其中的最小值返回即可。

参考题解https://leetcode.cn/problems/minimize-the-total-price-of-the-trips/solutions/2229503/lei-si-da-jia-jie-she-iii-pythonjavacgo-4k3wq/

class Solution {
public:
    int minimumTotalPrice(int n, vector<vector<int>>& edges, vector<int>& price, vector<vector<int>>& trips) {
        vector<vector<int>> g(n);
        for (auto e: edges) {
            // g[e[0]] = e[1];
            // g[e[1]] = e[0];
            int x = e[0], y = e[1];
            g[x].push_back(y);
            g[y].push_back(x);
        }

        vector<int> cnt(n);
        for (auto &t: trips) {
            int end = t[1];
            function<bool(int, int)> dfs = [&](int x, int fa) -> bool {
                if (x == end) {
                    ++cnt[x];
                    return true;
                }
                for (int y: g[x]) {
                    if (y != fa && dfs(y, x)) {
                        ++cnt[x];	// x 是 end 的祖先节点,要到达 end 一定会经过 x
                        return true;
                    }
                }
                return false;
            };
            dfs(t[0], -1);
        }

        function<pair<int, int>(int, int)> dfs = [&] (int x, int fa) -> pair<int, int> {
            int non_halve = price[x] * cnt[x];
            int halve = non_halve / 2;
            for (auto y: g[x]) {
                if (y != fa) {
                    auto [nh, h] = dfs(y, x);
                    non_halve += min(nh, h);
                    halve += nh;
                }
            }
            return {non_halve, halve};
        };
        auto [nh, h] = dfs(0, -1);
        return min(nh, h);
    }
};

其中,
y != fa 的判断是用来避免回头访问父节点,从而避免出现环路,确保在遍历树或图时不会重复访问同一个节点,同时也避免了在遍历过程中出现死循环。

另外注意这里C++的匿名函数的使用。

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值