盈利计划
难度:
标签:
题目描述
代码结果
运行时间: 307 ms, 内存: 16.6 MB
/*
题目思路:
1. 使用动态规划来解决问题。
2. 定义一个三维数组 dp,dp[i][j][k] 表示前 i 个工作中,使用 j 个员工,获得至少 k 利润的方案数。
3. 初始化 dp[0][0][0] = 1,表示不使用任何员工且没有利润的情况。
4. 遍历每个工作,并更新 dp 数组。
5. 对每个工作,考虑两种情况:不选该工作和选该工作。
6. 最后统计 dp 数组中利润至少为 minProfit 的方案总数。
*/
import java.util.stream.IntStream;
public class ProfitableSchemesStream {
public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
int MOD = 1000000007;
int length = group.length;
int[][][] dp = new int[length + 1][n + 1][minProfit + 1];
dp[0][0][0] = 1;
for (int i = 1; i <= length; i++) {
int members = group[i - 1];
int earn = profit[i - 1];
IntStream.rangeClosed(0, n).forEach(j -> IntStream.rangeClosed(0, minProfit).forEach(k -> {
dp[i][j][k] = dp[i - 1][j][k];
if (j >= members) {
dp[i][j][k] = (dp[i][j][k] + dp[i - 1][j - members][Math.max(0, k - earn)]) % MOD;
}
}));
}
return IntStream.rangeClosed(0, n).map(j -> dp[length][j][minProfit]).reduce(0, (a, b) -> (a + b) % MOD);
}
}
解释
方法:
这个题解使用了动态规划和容斥原理。首先使用动态规划求出员工数不超过n的所有组合数,然后再求出利润小于minProfit的组合数。最后根据容斥原理,用员工数不超过n的组合数减去利润小于minProfit的组合数,得到员工数不超过n且利润不小于minProfit的组合数。
时间复杂度:
O(n^2+n*minProfit)
空间复杂度:
O(n*minProfit)
代码细节讲解
🦆
在动态规划的实现中,dp1数组初始化为dp1[0] = 1的原理是什么?其他位置为什么初始化为0?
▷🦆
对于dp1数组中的更新操作`dp1[i] += dp1[i-g]`,这里的逻辑是如何确保不会重复计算同一组工作人员的不同组合?
▷🦆
在处理`dp2`数组时,为什么要从后向前更新,即对于内层循环为什么是`range(minProfit-1, p-1, -1)`?
▷🦆
题解中提到的容斥原理具体是如何应用的,在这个问题中它起到了什么作用?
▷