There is a group of n
members, and a list of various crimes they could commit. The ith
crime generates a profit[i]
and requires group[i]
members to participate in it. If a 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 minProfit
profit, and the total number of members participating in that subset of crimes is at most n
.
Return the number of schemes that can be chosen. Since the answer may be very large, return it modulo 10^9 + 7
.
思路:
第i次行动需要消耗人力group[i],并且获得利润profit[i],在总人力不超过n的情况下,有多少个行动组合满足利润不小于minProfit
熟悉的取模10^9 +7,大概率就是动态规划了
需要一个二维数组dp去记录之前i-1时 人力g、利润p对应的行动组合个数
当计算第i次行动时,当前的组合个数等于 g- group[i], p - profit[i]时的组合个数
因此得出状态转移方程:
dp[g][p] += dp[g-group[i]][p- profit[i]];
注意的问题:
- 初始值,dp[0][0]为1
- dp中人力和利润纬度都需要从大往小计算,从小往大会重复计算
- 大于当利润大等于minProfit时,总次数就记录在dp[g][ minProfit]中
- 当minProfit==0时,空集也是一个答案
代码
int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit) {
vector<vector<int> > dp(101, vector<int>(101,0));
int md = (1e9)+7, sm = (minProfit ==0);
dp[0][0] = 1;
for (int i = 0; i< group.size(); i ++) {
for (int j = n; j >= group[i]; j --) {
for (int k = minProfit; k >= 0; k --) {
if (k + profit[i] >= minProfit) {
(sm += dp[j- group[i]][k])%=md;
(dp[j][minProfit] += dp[j- group[i]][k]) %=md;
}
else {
(dp[j][k + profit[i]] += dp[j-group[i]][k]) %=md;
}
}
}
}
return sm;
}