1.问题描述
有n件物品和一个最大能背m重量的背包。其中,第i件物品的重量为wight[i],相对应的价值为value[i]。物品不能重复使用。试问,怎样放置物品可使得价值最大?
2.解决方案
使用动态规划方法进行求解。
(1)确定dp含义
dp[i][j]表示从[0-i]的物品中进行一次动作选择,放到容量为j的背包中,所获取的最大价值。
(2)状态转移方程
0-1背包的动作可分为两种:向背包中放入物品和不放入物品。因此:
dp[i][j]=max(dp[i-1][j-wight[i]]+value[i],dp[i-1][j]);
(3)初始化边界
需要对dp[i][0]和dp[0][j]进行初始化。
其中dp[0][j]的初始化应注意只能从后往前;如果从前往后会出现重复计算,例如:dp[0][2]=dp[0][1]+value[2]。
for(int j=bagwight; j>=wight[0];j--){
dp[0][j]=dp[0][j-wight[0]]+value[0];
}
(4)确定遍历顺序
1.先遍历背包,再遍历物品
2.先遍历物品,再遍历背包
(5)代码
int bag_problem(){
vector<int>wight={1,3,4};
vector<int>value={10,15,30};
int bagwight=4;
vector<vector<int>>dp(wight.size(), vector<int>(bagwight+1, 0));
for(int j=bagwight; j>=wight[0];j--){
dp[0][j]=dp[0][j-wight[0]]+value[0];
}
for(int j=1;j<=bagwight;++j){
for(int i=1;i<wight.size();++i){
if(j<wight[i]) dp[i][j]=dp[i-1][j];
else dp[i][j]=max(dp[i-1][j-wight[i]]+value[i],dp[i-1][j]);
}
}
return dp[wight.size()-1][bagwight];
}
3.使用一维数组解决0-1背包问题
(1)确定dp含义
dp[j]表示容量为j的背包的最大价值
(2)状态转移方程
dp[j]=max(dp[j], dp[j-wight[i]]+value[i])
(3)初始化
for(int j=0; j<=bagwight;++j){
dp[j]=0;
}
(4)遍历顺序
一维数组中,背包的遍历必须由大到小;保证一件物品放一次。
for(int i=0;i<wight.size();++i){
for(int j=bagwight;j>=wight[i];--j){
dp[j]=max(dp[j], dp[j-wight[i]]+value[i]);
}
}
在二维dp数组中,先物品后背包,和先背包后物品,均可以。
在一维dp数组中,必须先遍历物品,后遍历背包。