LC879. 盈利计划(动态规划(01背包)- 困难)

LC879 盈利计划

题目:集团里有 n 名员工,他们可以完成各种各样的工作创造利润。第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与。如果成员参与了其中一项工作,就不能参与另一项工作。
         工作的任何至少产生 minProfit 利润的子集称为 盈利计划 。  有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7 的值。
         (输入 n = 5, minProfit = 3, group = [2,2], profit = [2,3]  输出:2)
分析:动态规划(背包问题)
        员工:    0-n
        工作: 产生利润 profit  使用员工 group  0 - work
        利润:  0 - minProfit
        (想想和 LC474 0和1(findMaxForm)题目的相似之处
            每个单词                                           对应   本题中的一份工作
            单词包含0和1的个数                         对应  一份工作 需要的人数 和  产生的效益
            0和1问题中状态值是字符串的总量   对应  本题中的状态值为产生利润至少为 k 的方案数        )

        状态:  d[i][j][k]   当做第i个工作 员工在前j个员工中选择  产生利润为【至少为k】 的方案数
        状态转移方程:
                d[i][j][k] = max(前i-1份工作产生利润至少为k的方案数,前i-1份工作产生利润至少为k的方案数 + 做了当前工作后剩余“空间”的方案数)
                            = max(d[i-1][j][k], d[i-1][j][k] + d[i-1][j-group[i-1]][max(0,k-profit[i-1])])
                           %因为利润至少为k,所以有以下两种情况:
                                ① 如果 profit[i-1] < k   则 可待赚的钱为 k - profit[i-1]
                                ② 如果 profit[i-1] >= k  则 代表当前的钱已经赚够了  如果再分配人 划水就可以了  所以  此时待赚的钱为  0    故 第二项取值为  max(0, k-profit[i-1])                

          状态初始化:
          工作 i    范围 [0, work]  当工作i为0时     d[0][:][0]=1  其他为0     即 没有工作 有多少员工 都不会产生效益  有一种方案
           员工 j    范围 [0, n]      当员工j为0时     d[:][0][0]=1  其他为0      即 有再多的工作 没有员工 也不会产生效益 有一种方案
           利润 k    范围 [0, minprofit]   当利润k至少为0时  该初始化需要用到上边推出来的动态方程   因为工作是可以选择的  不一定是0才能使得收益是0  所以是符合上边分析的状态转移规律的
           那么 我们初始化 需要初始  d[0][:][0]=1 和 d[:][0][0]=1   在遍历时候 ij均从1开始  k从0开始
复杂度: 时间复杂度O(work*n*minprofit)  空间复杂度O(work*n*minprofit)

PS:注意本题与之前01背包问题不同的点是,本题求解的至少产生minprofit利润的方案。

代码:

def profitableSchemes(n, minProfit, group, profit):
    work, MOD = len(group), int(1e9 + 7)
    # i → work   j → n  k → minprofit
    d = [[[0 for _ in range(minProfit + 1)] for _ in range(n + 1)] for _ in range(work + 1)]

    for j in range(n + 1):
        d[0][j][0] = 1
    for i in range(work + 1):
        d[i][0][0] = 1

    for i in range(1, work + 1):
        for j in range(1, n + 1):
            for k in range(minProfit + 1):
                if j >= group[i - 1]:
                    d[i][j][k] = (max(d[i - 1][j][k],
                                      d[i - 1][j][k] + d[i - 1][j - group[i - 1]][max(0, k - profit[i - 1])])) % MOD
                else:
                    d[i][j][k] = d[i - 1][j][k]
    return d[-1][-1][-1]

路虽远,行则将至。事虽难,做则必成 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值