前提
01背包 = 完全背包 + 物品个数控制
完全背包与01背包不同就是: 完全是每种物品可以有无限多个,01背包每种物品只有一个,放进去就没有了。所以代码也是从 完全背包的基础上添加 物品的个数控制。
完全背包参考:算法.动态规划.完全背包问题 (Java,递归)https://blog.csdn.net/weixin_42754896/article/details/123068850
01背包问题
在N个物品取出若干件放在容量为W的背包里,每个物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数)。
求背包能够容纳的最大价值。
说明:每个东西只有一个,装进去就没有了
穷举画图
东西编号 : D1 D2 D3 D4
体积W : 2 3 4 5
价值V : 3 4 5 6
背包体积W:8
假设有两个东西:D1 D2 D3,每次选择都从剩下的选择,直到包里装不下东西(根据体积来算,或者拿不了(根据重量))。
F(W)
D1 D2 D3 ---- 第一次选择
D2 D3 D1 D3 D1 D2 ---- 第二次选择
D1 D2 D3 D1 D3 D1 ---- 第三次选择
……
F(8): 装满体积8的最大价值
D1.W: D1东西的体积
D2.V: D2东西的价值
F(W) = Max( F(W-D1.W) + D1.V,F(W-D2.W)+D2.V )
变的是:每次的选项都会减少
代码
@Test
public void test1(){
/**
* 体积W : 2 3 4 5
* 价值V : 3 4 5 6
*/
Dong [] dongs =new Dong[4];
dongs[3] = new Dong(2,3);
dongs[2] = new Dong(3,4);
dongs[1] = new Dong(4,5);
dongs[0] = new Dong(5,6);
// 背包体积
int w = 8;
// 问题:求 钱的张数最小
Solution Solution = new Solution();
byte [] seleted = new byte[dongs.length];
Assert.assertEquals(10, Solution.maxValue01(dongs,w,seleted));
}
class Solution {
public int maxValue01(Dong[] dongs,int w,byte [] seleted) {
if(w <= 0){
return 0;
}
int maxValue = 0;
int tempMaxValue = 0;
for(int i = 0 ; i < dongs.length ; i++,tempMaxValue = 0){
// 如果选择了,跳过去
if(seleted[i] == 1){
continue;
}
if(dongs[i].w > w){
// 背包装不下:当前东西的体积直接比背包大,装个屁直接忽略
continue;
}else if(dongs[i].w <= w){
// 标记已经选择
seleted[i] = 1;
/**
* 背包装得下:东西体积跟背包体积一样大,或者小于
* 剩余体积能装最大的价值 + 当前装的东西的价值
* F(W) = Max( F(W-D1.W) + D1.V, F(W-D2.W)+D2.V )
*/
tempMaxValue = maxValue01(dongs , w - dongs[i].w,seleted) + dongs[i].v;
}
// 如果这种币值的钱张数 比较少就记录
if(tempMaxValue > maxValue){
maxValue = tempMaxValue;
}
// 要遍历下一个了自然需要清除
seleted[i] = 0;
}
return maxValue;
}
}
class Dong{
public int w;
public int v;
public Dong(){}
public Dong(int w,int v){
this.w = w;
this.v = v;
}
}
end