标签:思路 ddl ash pat public table 应该 情况 就是
今天是个困难题。
集团里有 n 名员工,他们可以完成各种各样的工作创造利润。
第 i 种工作会产生 profit[i] 的利润,它要求 group[i] 名成员共同参与。如果成员参与了其中一项工作,就不能参与另一项工作。
工作的任何至少产生 minProfit 利润的子集称为 盈利计划 。并且工作的成员总数最多为 n 。
有多少种计划可以选择?因为答案很大,所以 返回结果模 10^9 + 7 的值。
示例
输入:n = 5, minProfit = 3, group = [2,2], profit = [2,3]
输出:2
解释:至少产生 3 的利润,该集团可以完成工作 0 和工作 1 ,或仅完成工作 1 。
总的来说,有两种计划
从示例来看,不难看出题目的意思,最直接的思路就是每项工作都可以选,或者不选。如果选择做这个工作,则在扣除该工作的人数和盈利之后,看是否满足要求,如满足要求,结果加1。如果不选择这个工作,则继续往下遍历,最先想到的解决方案是深度优先算法,一般深度优先算法都会超时,但是为了验证思路对不对,先写一个出来看看效果。
1 public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) { 2 3 Set<List<Integer>> valueSet= new HashSet<>(); 4 dfs(n,minProfit,group,profit,0,valueSet); 5 return valueSet.size(); 6 } 7 LinkedList<Integer> path = new LinkedList<>(); 8 private void dfs(int n, int minProfit, int[] group, int[] profit, int currIdx,Set<List<Integer>> valueSet){ 9 if(n<0||(n==0&&minProfit>0)){ 10 return; 11 } 12 if(minProfit<=0){ 13 valueSet.add(new ArrayList<>(path)); 14 } 15 for(int i = currIdx;i<group.length;i++){ 16 path.addLast(i); 17 dfs(n-group[i],minProfit-profit[i],group,profit,i+1,valueSet); 18 path.removeLast(); 19 dfs(n,minProfit,group,profit,i+1,valueSet); 20 21 } 22 23 }
因为遍历的时候有些结果集会重复计算,所以使用Set来过滤一下,也没有考虑到题目要求结果需要模1e9+7。将题目中的示例输入,结果是对的,起码方向对了,提交超时。
其实这种题目,求最值(最多,最少)的大部分都可以用动态规划来做,所以我们考虑动态规划。
根据以上深度优先算法的参数可知,动态规划涉及的维度有3个,n,group.length,minprofit,所以首先可以开一个三维数组。
int[][][] dp = new int[group.length+1][n+1][[minprofit+1]
然后我们来思考一下数据之间的关联,工作只有两种选择,选与不选,如果不选择,当前的值应该等于之前的值,即:
dp[i][j][k]=dp[i-1][j][k]
如果选择,则当前的值应为之前的值在人数和盈利减去当前项的值,即:
dp[i][j][k]=dp[i-1][j-group[i]][k-profit[i]]
最终的值为两者相加,即:
dp[i][j][k]=dp[i-1][j][k]+dp[i-1][j-group[i]][k-profit[i]]
接下来,需要注意的是:
1.如果选择该项工作,需保证j>group[i],否认只能不选
2.k-profit[i]有可能为负值,一般解决负值的方法就是开双倍的空间来存储,以模拟存储负值的情况,这里不需要,因为盈利为负值可以都计算在满足条件,即profit为0的情况。
基于上述分析,最终的版本。
public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) { int mod = (int) 1e9+7; int m = group.length; int[][][] dp = new int[m+1][n+1][minProfit+1]; for(int i = 0;i<n+1;i++){ dp[0][i][0]=1; } for(int i =1;i<=m;i++){ int gs= group[i-1]; int ps = profit[i-1]; for(int j = 0;j<=n;j++){ for(int k = 0;k<=minProfit;k++){ dp[i][j][k]=dp[i-1][j][k]; if(j>=gs){ dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-gs][Math.max(k-ps,0)])%mod; } } } } return dp[m][n][minProfit]; }
标签:思路 ddl ash pat public table 应该 情况 就是
原文地址:https://www.cnblogs.com/jejas/p/14869351.html