LeetCode 879. 盈利计划

879. 盈利计划

本题与经典背包问题非常相似。两者不同点在于经典背包问题只有一种容量限制,而本题却有两种限制:集团员工人数上限 n,以及工作产生的利润下限 minProfit。

通过经典背包问题的练习,我们已知经典背包问题可以使用二维动态规划求解:两个维度分别代表物品和容量的限制标准。

对于本题上述的两种限制,我们可以想到使用三维动态规划求解。

本题解法的三个维度分别为:当前可选择的工作,已选择的小组员工人数,以及目前状态的工作获利下限。

根据上述分析,我们可以定义一个三维数组 dp 作为动态规划的状态,其中 dp[i][j][k] 表示在前 i 个工作中选择了 j 个员工,并且满足工作利润至少为 k 的情况下的盈利计划的总数目。假设 group 数组长度为 len,那么不考虑取模运算的情况下,最终答案为:

在这里插入图片描述

所以我们可以新建一个三维数组 dp[len+1][n+1][minProfit+1],初始化 dp[0][0][0]=1。接下来分析状态转移方程,对于每个工作 i,我们根据当前工作人数上限 j,有能够开展当前工作和无法开展当前工作两种情况:

  • 如果无法开展当前工作 i,那么显然:
    在这里插入图片描述
  • 如果能够开展当前工作 i,设当前小组人数为 group[i],工作获利为 profit[i],那么不考虑取模运算的情况下,则有:

在这里插入图片描述
由于我们定义的第三维是工作利润至少为 k 而不是 工作利润恰好为 k,因此上述状态转移方程中右侧的第三维是 max(0,k−profit[i]) 而不是 k−profit[i]。读者可以思考这一步的妙处所在。

Code

Python

class Solution:
    def profitableSchemes(self, n: int, minProfit: int, group: List[int], profit: List[int]) -> int:
        MOD = 10 ** 9 + 7
        length = len(group)
        dp = [[[0] * (minProfit + 1) for _ in range(n + 1)] for _ in range(length + 1)]
        dp[0][0][0] = 1

        for i in range(1, length + 1):
            # 第 i 个工作要求参与的员工数量和会产生的利润
            members, earn = group[i - 1], profit[i - 1]
            for j in range(n + 1):
                for k in range(minProfit + 1):
                    if j < members:  # 如果当前工作人数上限小于需要求参与的员工数量则无法开展此工作
                        dp[i][j][k] = dp[i - 1][j][k]
                    else:
                        dp[i][j][k] = (dp[i - 1][j][k] + dp[i - 1][j - members][max(0, k - earn)]) % MOD

        total = sum(dp[length][j][minProfit] for j in range(n + 1))
        return total % MOD

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/profitable-schemes/solution/ying-li-ji-hua-by-leetcode-solution-3t8o/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大风车滴呀滴溜溜地转

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值