你的背包让我走得好缓慢,借了终于陪着我腐烂
1. 0/1背包
有一个腐烂的背包,容量为v,现有n件物品,每件物品有两个属性,体积v_i,和价格p_i,我们要选择物品往背包里放,使得在物品总容积不超过v的情况下价值最大。
思路:
设 dp[n][v] 前n件物品,背包总容量为v时的最大价值。
1)当我们想要放物品 i 时, 就要为他预留 v_i 的空间,那么背包的总容量就会下降 v_i, 剩下的容量 v - v_i去放其他物品,如果不放物品 i, 那么不用预留空间,空间仍然为 v,对于放还是不放,当然是取决于总价值的大小,即 max( dp[i-1][v-v_i] + p_i, dp[i-1][v]), 这样就从根部引出了两个分支,每个分支又会引出来两个分支,最终形成一棵二叉树,从根到叶子结点,左子树为0,右子树为1,相当于将所有情况枚举了出来,但是区别之处在于不同分支是会出现相同子状态的,这就避免了重复计算。
2)In fact, 某些分支是不一定能到达叶子结点的,即如果某一分支的某个结点加入后,总容量超了,那么这条路径就无法继续延续了。
解法:
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),一直迭代。详细解释见【动态规划】01背包问题(通俗易懂,超基础讲解)_Yngz_Miao的博客-CSDN博客_动态规划解决01背包问题
2. 完全背包
在完全背包中是不限制每件物品的数量的,而0/1背包是每种物品只有一件。此时的问题不是针对每种物品放或不放(放0个或1个),而是放几个的问题(放0个,1个,2个。。。。or n个),这里物品i最多放maxSpace//vi件。因此我们在放每件物品的时候要多加一个循环,分别算出maxValue(i,v)在物品i取0至maxSpace//vi件时的值,取最大的作为maxValue[i][v]的最终值。动态规划填表一行一行的填。详细见【动态规划】完全背包问题 - 弗兰克的猫 - 博客园
3.多重背包
每种物品的数量为num[i]个,完全背包的物品数是无限的,多重背包是有限个。和完全背包基本相同,核心是每种物品放几个,从0~num[i], 个数不超过num[i]的同时空间也不能超过背包容量,详细见【动态规划】多重背包问题 - 弗兰克的猫 - 博客园
#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;
}
我不生产知识,我只是知识的搬运工------农夫