【无标题】

文章介绍了在LeetCode题目中如何通过两次操作(删除没有操作必要性的叶子节点和删除含有金币的叶子节点)来确定在树形结构中收集金币所需的最小步数。算法利用拓扑排序减少不必要的边数计算最终结果。
摘要由CSDN通过智能技术生成


定义一个变量 cnt ,记录此时图中剩余的边数,初始时为 n-1

1. 删除没有操作必要性的节点

对于下图所示的示例
在这里插入图片描述
(灰色表示没有金币,金色表示有金币) 节点6和节点9就属于没有必要操作的节点,我们把度为1的节点定义为叶子节点,那么节点6和节点9就是属于没有金币的叶子节点,这些节点没有操作的必要性,因此是可以去除的。如果去除过程中又产生了新的叶子节点,那么也一并去除;

我们选用拓扑排序来去除,对于某一个节点 u ,如果其没有金币并且度数为1,那么该节点就属于此次操作要去除的节点,并且去除 u 时,与之相邻的其他节点 v 度数也需要减少,每次删除一个叶子节点 u , cnt 减少1

2. 删除范围2内的节点

在这里插入图片描述
对于操作1后,图的情况如上图所示,由于可以收集距离当前节点距离为 2 以内的所有金币,因此,我们不必要到达金币所在的节点,而只需要到达金币所在节点的父节点的父节点,就可以收集到该金币. 那么我们就可以把含有金币的叶子节点去掉,并一并去掉过程中产生的其他叶子节点;而剩下的节点,就是必须要访问的节点;每去掉一个节点,cnt 减 1
在这里插入图片描述

3. 得出结果

通过上述两个操作之后,剩余的节点就是必须要访问的节点,无论此时从哪个节点出发(1,2,0) 都必须要原路去原路回,因此,需要走的步数都是剩余的边数 cnt 的两倍

class Solution {
public:
    int collectTheCoins(vector<int>& coins, vector<vector<int>>& edges) {
        int n = coins.size();
        vector<vector<int>> edge(n);
        vector<int> deg(n, 0);
        for (const auto& e : edges) {
            int u = e[0];
            int v = e[1];
            edge[u].emplace_back(v);
            edge[v].emplace_back(u);
            deg[u]++;
            deg[v]++;
        }
        // 记录剩余的边数
        int leftEdges = n - 1;
        queue<int> q;

        // 操作1,去掉没有操作必要的叶子节点
        for (int i = 0; i < n; i++) {
            if (deg[i] == 1 && coins[i] == 0)
                q.emplace(i);
        }
        while (!q.empty()) {
            leftEdges--;
            int u = q.front();
            q.pop();
            for (const auto& v : edge[u]) {
                if (--deg[v] == 1 && coins[v] == 0)
                    q.emplace(v);
            }
        }

        // 操作2 ,去掉含有金币的叶子节点,并且一并去掉过程中产生的新的叶子节点
        for (int i = 0; i < n; i++) {
            if (deg[i] == 1 && coins[i] == 1)
                q.emplace(i);
        }
        // 更新剩余边数
        leftEdges -= q.size();
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            for (int v : edge[u]) {
                if (--deg[v] == 1)
                    leftEdges--;
            }
        }
        // 剩余的边数就是必须要访问的边数,可能为负数(假如一开始就只有两个节点并且都有金币)
        return max(2 * leftEdges, 0);
    }
};

参考题解:灵茶山艾府 链接:https://leetcode.cn/problems/collect-coins-in-a-tree/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值