你的背包让我走得好缓慢,借了终于陪着我腐烂
1. 0/1背包
有一个腐烂的背包,容量为v,现有n件物品,每件物品有两个属性,体积w,和价格p,我们要选择物品往背包里放,使得在物品总容积不超过v的情况下价值最大。
思路:
1)我们只在乎某件物品放不放进背包,而不在乎放进去的顺序,因为物品一样,顺序不一样,结果相同。
2)我们从第一件物品开始考虑,只有两种情况,放或不放,然后考虑第二件物品,放或不放,。。。。。。第n件物品放或不放。
3)放则记为1,不放记为0.那么假如共4件物品,所有可能的情况为0000,0001,0010,0011.....1111共16种情况。只要枚举完这16种情况我们就知道最大价值是多少。
4)虽然上面说有16种情况,但实际上有些情况是不存在的,例如1111,放入第四个物品会超出背包容量,所以应为1110。
5)我们定义maxValue(n,v)为容量为v时,选取物品1~n中若干件所能得到的最大价值。我们从第n件到第1件物品依次判断是否选取,每步都有下面的公式。不选maxValue(n-1,v),选maxValue(n-1,v-Vn)+Pn,取max
0 1
---maxValue(n,v)=max(maxValue(n-1,v), maxValue(n-1,v-Vn)+Pn),
当第k件物品遇到Vrest<Vk那么第k件物品只能不选取:
---maxValue(n,v)=maxValue(n-1,v)
这样在边界的时候我们是可以直接得出结果的,然后回溯得出maxValue(n,v)。
解法:
1)我们可以用递归函数来求,注意的是要用一个temp[n][v]数组存储已经求过的maxValue(n,v)来避免重复计算,因为到达状态[n,v]的可能不止一种情况。
2)用动态规划,递归是自顶向下,到达边界在回溯,而动态规划则是直接自底向上。
每个maxValue(n,v)关联的状态只有maxValue(n-1,v)或maxValue(n-1,v-Vn).所以我们我们填一个n+1行v+1列的表,从maxValue(0,0)一直到maxValue(n,v),一直迭代。详细解释见https://blog.csdn.net/qq_38410730/article/details/81667885
2. 完全背包
在完全背包中是不限制每件物品的数量的,而0/1背包是每种物品只有一件。此时的问题不是针对每种物品放或不放(放0个或1个),而是放几个的问题(放0个,1个,2个。。。。or n个),这里物品i最多放maxSpace//vi件。因此我们在放每件物品的时候要多加一个循环,分别算出maxValue(i,v)在物品i取0至maxSpace//vi件时的值,取最大的作为maxValue[i][v]的最终值。动态规划填表一行一行的填。详细见https://www.cnblogs.com/mfrank/p/10803417.html
3.多重背包
每种物品的数量为num[i]个,完全背包的物品数是无限的,多重背包是有限个。和完全背包基本相同,核心是每种物品放几个,从0~num[i], 个数不超过num[i]的同时空间也不能超过背包容量,详细见https://www.cnblogs.com/mfrank/p/10816837.html
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(){
int space,kind;
cin>>space>>kind;
vector<vector<int>>data(kind+1,vector<int>(3,0));
vector<vector<int>>dp(kind+1,vector<int>(space+1,0));
//space price num
//注意这里是从1开始,只有物品1~kind,没有物品0
for(int i=1;i<kind+1;i++)cin>>data[i][0]>>data[i][1]>>data[i][2];
for(int i = 1; i<kind+1;i++){
for(int j=1;j<space+1;j++){
for(int k=0;k<=data[i][2]&&j>=k*data[i][0];k++){//0表示不选,注意选的第i件物品总体积不超过当前的容量
//由于这里考虑的是选k件物品的数量,所有下面每次减掉的空间是k*data[i][0],增加的价值是k*data[i][1]
dp[i][j]=max(dp[i][j],dp[i-1][j-k*data[i][0]]+k*data[i][1]);
}
}
return 0;
}
我不生产知识,我只是知识的搬运工------农夫