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 <= G <= 100
0 <= P <= 100
1 <= group[i] <= 100
0 <= profit[i] <= 100
1 <= group.length = profit.length <= 100
根据题目所述,这是一道背包问题。背包容量为G
,group
和 profit
中分别的数值分别表示每一件物品的体积(或重量) 和 价值。另外,题目中加入的一个限制条件: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;
}
};