力扣2920 收集所有金币可获得的最大积分

题目链接:https://leetcode.cn/problems/maximum-points-after-collecting-coins-from-all-nodes/description/

解题思路:

最大积分(最优化解)+树形结构 + n~1e5 基本可以确定这道题要么o(n)(贪心,记忆化)要么dp。

尝试用dp来解,有一个主要洞察点:除以2这个操作其实执行不了多少次数就会被除没(变成0)。

题中的两种收集金币的方式一种会导致收集金币值-k,另一种会导致当前收集金币减半且后续子树上的金币全部减半。其中子树金币减半这个操作如果用代码来模拟则会消耗巨大的时间,所以我们考虑能否对这个操作进行记忆化或者说是dp,从而优化时间复杂度。

如果你能观察到上面的洞察点,那么dp就很好解决了,也就是说除2的次数可以被当成一个维度来构造dp算法(因为10000最多除14次就变成0了)。

定义 dp[i][j]i号节点对应的子树除以2^j以后 能够得到的最大值。
那么状态转移也顺理成章的出来了:

m a x ( ∑ x d p [ x ] [ j ] + c o i n s [ i ] / 2 j − k , ∑ x d p [ x ] [ j + 1 ] + c o i n s [ i ] / 2 j + 1 ) max(\sum_{x} dp[x][j]+coins[i]/2^j-k\quad, \sum_{x} dp[x][j+1]+coins[i]/2^{j+1}) max(xdp[x][j]+coins[i]/2jk,xdp[x][j+1]+coins[i]/2j+1)

CPP代码:

class Solution {
public:
    void dfs(int cur,int par,vector<vector<int>>& edge, vector<vector<int>>& dp, vector<int>& coins, int k)
    {
        for(int i=0;i<edge[cur].size();i++)
            if(edge[cur][i]!=par)dfs(edge[cur][i],cur,edge,dp,coins,k);
        for(int j=0;j<15;j++) //2^14=16,384 > 10,000,顶多除14次就为0了,这里设大点也没关系
        {
            int sum1=0,sum2=0;
            for(int i=0;i<edge[cur].size();i++)
            {
                int x=edge[cur][i];
                if(x==par)continue;
                sum1+=dp[x][j];
                sum2+=dp[x][j+1];
            }
            dp[cur][j]=max(sum1+(coins[cur]>>j)-k,sum2+(coins[cur]>>(j+1)));
        }
        return ;
    }
    int maximumPoints(vector<vector<int>>& edges, vector<int>& coins, int k) {
        vector<vector<int>> edge(coins.size());
        vector<vector<int>> dp(coins.size(),vector<int>(16,0));
        for(int i=0;i<edges.size();i++)
        {
            edge[edges[i][0]].push_back(edges[i][1]);
            edge[edges[i][1]].push_back(edges[i][0]);
        }
        dfs(0,-1,edge,dp,coins,k);
        return dp[0][0];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值