LeetCode 879. Profitable Schemes

一、题目描述

There are G people in a gang, and a list of various crimes they could commit.

The i-th crime generates a profit[i] and requires group[i] gang members to participate.

If a gang member participates in one crime, that member can’t participate in another crime.

Let’s call a profitable scheme any subset of these crimes that generates at least P profit, and the total number of gang members participating in that subset of crimes is at most G.

How many schemes can be chosen? Since the answer may be very large, return it modulo 10^9 + 7.

Example 1:

Input: G = 5, P = 3, group = [2,2], profit = [2,3]
Output: 2
Explanation:
To make a profit of at least 3, the gang could either commit crimes 0 and 1, or just crime 1.
In total, there are 2 schemes.

Example 2:

Input: G = 10, P = 5, group = [2,3,5], profit = [6,7,8]
Output: 7
Explanation:
To make a profit of at least 5, the gang could commit any crimes, as long as they commit one.
There are 7 possible schemes: (0), (1), (2), (0,1), (0,2), (1,2), and (0,1,2).

Note:

  1. 1 <= G <= 100
  2. 0 <= P <= 100
  3. 1 <= group[i] <= 100
  4. 0 <= profit[i] <= 100
  5. 1 <= group.length = profit.length <= 100

 


 

二、题目分析

  根据题目所述,这是一道背包问题。背包容量为Ggroupprofit 中分别的数值分别表示每一件物品的体积(或重量)价值。另外,题目中加入的一个限制条件:P ,表示放入背包的物品的总最小价值,即放入背包的所有物品的总价值要大于等于 P 。最后求出有多少种放物品进背包的方案能够满足条件(总价值大于等于 P

  按照动态规划的思路,用 res[i][j] 表示背包内物品总重量为 i ,总价值大于等于 j 的方案总数。
  一件一件物品来处理,当我们决定要把一件体积为 group[k] ,价值为 profit[k] 的物品 k 放入背包的时候,只有那些放入该物品后,背包内物品总体积未超过背包容量的方案中的背包才能装入该物品,我们相应地更新这些方案再放入该物品后的方案数,即有递推式:

res[i][j] += res[i-group[k]][j-profit[k]]

  当然,这里 i-group[k] 必须大于0,即之前的背包是能够放入物品 k 的;若 j-profit[k] < 0 ,则说明之前的背包放入物品 k 后,总价值已经大于 j 了,所以此时用0代替( res[n][m] 表示的方案包含 res[n][m+1] 的方案)。

  至此,问题大致解决。

 


 

三、具体实现

  复杂度如上分析,为 O ( N G P ) O(NGP) O(NGP) ,其中 N N N 为物品的个数, G G G 为背包容量, P P P 为限制条件的最小价值。
  从递推式可看出,对于每一个物品,计算每一个 res[i][j] 需要放这个物品之前的 res 数据,所以我们 从后往前 遍历计算 res[i][j]

class Solution
{
  public:
    int profitableSchemes( int G, int P, vector<int> &group, vector<int> &profit )
    {
        vector<vector<int>> res( G + 1, vector<int>( P + 1, 0 ) );
        res[0][0] = 1;

        int n = group.size(), mod = 1e9 + 7;

        for ( int k = 0; k < n; ++k ) {
            for ( int i = G; i >= group[k]; --i ) {
                for ( int j = P; j >= 0; --j ) {
                    res[i][j] = ( res[i][j] + res[i - group[k]][max( 0, j - profit[k])] ) % mod;
                }
            }
        }

        int sum = 0;
        for ( int i = 0; i <= G; ++i )
            sum = ( sum + res[i][P] ) % mod;

        return sum;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值