多属性背包进阶--盈利计划
Posted C_YCBX Py_YYDS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多属性背包进阶--盈利计划相关的知识,希望对你有一定的参考价值。
题目
题目解析
- 题目描述第i种工作产生两个属性–产生的利润和需要的人数。
- 而题目的含义在于:给你
n
个员工,问给他们分配工作后,产生至少是minProfit
利润的计划总数(即不同的分配工作情况)。
这与之前做过的一道多属性背包不可谓不相同:字符串装0和1
分析:
- 此题明显和之前所做过的一道多属性背包类似,只不过这题的多属性较难看出,这题的属性也是两个,员工人数和所需的最小利润数,故根据这两个属性构建背包得
dp
关系dp[i][j][k] = dp[i-1][j][k](no pack) + dp[i-1][j-group[i-1]][max(0,k-profit[i-1])]
,这里的dp[i][j][k] 的含义是在前i份工作的选择中,背包中有j名员工和要求至少是k的利润限制下的计划总数
。 - 这与之前的多属性背包唯一的不同在于背包的第二个属性要求的是至少是k的利润而不是正好是k,所以我们通过
max(0,k-profit[i-1])
以保证大于或者等于k都能被计数base case dp[0][0][0] = 1
; - 最后得到的答案需要的是所有盈利计划利润大于
minProfit
的情况,所以需要将员工[0-n]
的情况都加上。
由于题目要求结果要返回模10e9+7
的结果,可以在求dp的时候得到每个dp[i][j][k]%MOD
,然后最后再集体相加再模一次得结果。原理在于MOD运算的扩展:(a+b+c+d)%mod =(a%mod+b%mod+c%mod...)%mod
.也可以(a+b+c)%mod = ((a+0)%mod+b)%mod+c)%mod
。
解题代码
三维数组实现
class Solution {
public:
int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit) {
int MOD = 1e9 + 7;
int size = group.size(); int dp[size+1][n+1][minProfit+1];
memset(dp,0,sizeof(dp)); dp[0][0][0] = 1;
//这一层表示枚举工作(物品)
for(int i=1;i<=size;i++){
//这一层表示枚举员工(背包容量/物品属性)
for(int j=0;j<=n;j++){
//这一层表示枚举最小利润(背包容量/物品属性)
for(int k=0;k<=minProfit;k++){
if(j>=group[i-1])
dp[i][j][k] = (dp[i-1][j][k]+dp[i-1][j-group[i-1]][max(0,k-profit[i-1])])%MOD;
else
dp[i][j][k] = dp[i-1][j][k];
}
}
}//由于题目要求的是给你n名员工,以及i份工作,要求必须达到minProfit的计划数,所以由于dp的定义,则可选择对象为i个以及minProfit是确定的,而员工n人随便如何分配,只要达到minProfit的计划都算。
int res = 0;
//如果不这样取模,最后再取,则int会溢出,这个方法叫做反复取模法,利用两个数的不断取模,得到最终答案。=>(a+b+c)%mod = ((a+0)%mod+b)%mod+c)%mod
for(int i=0;i<=n;i++)res = (res + dp[size][i][minProfit])%MOD;
return res;
}
};
压缩一维得到二维形式
很明显可以压缩做外面一维。为了保证是上一行需要逆序遍历。
class Solution {
public:
int profitableSchemes(int n, int minProfit, vector<int>& group, vector<int>& profit) {
int MOD = 1e9 + 7;
int size = group.size(); int dp[n+1][minProfit+1];
memset(dp,0,sizeof(dp)); dp[0][0] = 1;
//这一层表示枚举工作(物品)
for(int i=1;i<=size;i++){
//这一层表示枚举员工(背包容量/物品属性)
for(int j=n;j>=0;j--){
//这一层表示枚举最小利润(背包容量/物品属性)
for(int k=minProfit;k>=0;k--){
if(j>=group[i-1])
dp[j][k] = (dp[j][k]+dp[j-group[i-1]][max(0,k-profit[i-1])])%MOD;
else
dp[j][k] = dp[j][k];
}
}
}//由于题目要求的是给你n名员工,以及i份工作,要求必须达到minProfit的计划数,所以由于dp的定义,则可选择对象为i个以及minProfit是确定的,而员工n人随便如何分配,只要达到minProfit的计划都算。
int res = 0;
//如果不这样取模,最后再取,则int会溢出,这个方法叫做反复取模法,利用两个数的不断取模,得到最终答案。=>(a+b+c)%mod = ((a+0)%mod+b)%mod+c)%mod
for(int i=0;i<=n;i++)res = (res + dp[i][minProfit])%MOD;
return res;
}
};
以上是关于多属性背包进阶--盈利计划的主要内容,如果未能解决你的问题,请参考以下文章