Trace
6.9 每日一题
传送门:https://leetcode-cn.com/problems/profitable-schemes/
Problem
集团里有 n
名员工,他们可以完成各种各样的工作创造利润。
第 i
种工作会产生 profit[i]
的利润,它要求 group[i]
名成员共同参与。如果成员参与了其中一项工作,就不能参与另一项工作。
工作的任何至少产生 minProfit
利润的子集称为 盈利计划 。并且工作的成员总数最多为 n
。
有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7
的值。
示例
1 2 3 4 5 6 7 8 9
| 输入:n = 5, minProfit = 3, group = [2,2], profit = [2,3] 输出:2 解释:至少产生 3 的利润,该集团可以完成工作 0 和工作 1 ,或仅完成工作 1 。 总的来说,有两种计划。
输入:n = 10, minProfit = 5, group = [2,3,5], profit = [6,7,8] 输出:7 解释:至少产生 5 的利润,只要完成其中一种工作就行,所以该集团可以完成任何工作。 有 7 种可能的计划:(0),(1),(2),(0,1),(0,2),(1,2),以及 (0,1,2) 。
|
数据范围
1 2 3 4 5 6
| 1 <= n <= 100 0 <= minProfit <= 100 1 <= group.length <= 100 1 <= group[i] <= 100 profit.length == group.length 0 <= profit[i] <= 100
|
思路
三维$dp$,考虑为什么用三维,首先考虑前$i$个员工,成员数限制(类似背包问题的体积),利润(类似背包问题价值),属性是方法种数,很自然就会想到三维。
f[i][j][k]: 考虑前i种工作,代价恰好为j,获得至少利润k的方法种数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| class Solution { public: int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit) { int sum=0; int count=0; for(int i=0;i<profit.size();i++){ sum+=profit[i]; } const int mod = 1e9+7; int f[101][101][101]; f[0][0][0]=1; for(int i=1;i<=group.size();i++){ for(int j=0;j<=n;j++){ for(int k=0;k<=minProfit;k++){ f[i][j][k]=f[i-1][j][k]; if(j>=group[i-1]){ f[i][j][k]=(f[i][j][k]+f[i-1][j-group[i-1]][max(0,k-profit[i-1])])%mod; } } } } for(int i=0;i<=n;i++){ count=(count+f[group.size()][i][minProfit])%mod; } return count; } };
|
f[i][j][k]=(f[i][j][k]+f[i-1][j-group[i-1]][max(0,k-profit[i-1])])%mod;
当中max(0,k-profit[i-1])
其实相当于
if((k-profit[i-1])>=0)
,f[i][j][k]=(f[i][j][k]+f[i-1][j-group[i-1]][k-profit[i-1]])%mod;
else
,f[i][j][k]=(f[i][j][k]+f[i-1][j-group[i-1]][0])%mod;
另一种写法:
f[i][j][k]: 考虑前i种工作,代价至多为j,获得至少利润k的方法种数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| class Solution { public: int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit) { int sum=0; int count=0; for(int i=0;i<profit.size();i++){ sum+=profit[i]; } const int mod = 1e9+7; int f[101][101][101]; for(int i=0;i<=group.size();i++){ for(int j=0;j<=n;j++){ f[i][j][0]=1; } }
for(int i=1;i<=group.size();i++){ for(int j=0;j<=n;j++){ for(int k=0;k<=minProfit;k++){ f[i][j][k]=f[i-1][j][k]; if(j>=group[i-1]){ f[i][j][k]=(f[i][j][k]+f[i-1][j-group[i-1]][max(0,k-profit[i-1])])%mod; } } } } return f[group.size()][n][minProfit]%mod; } };
|
$dp$数组要根据具体意义来初始化。
还可以优化到二维,类似01背包。