目录
前言
该问题是“最少钱币数问题”的延伸,整个代码结构类似,如果不了解可先参考:
完全背包问题
在N件物品取出若干件放在容量为W的背包里,每种物品的体积为W1,W2……Wn(Wi为整数),与之相对应的价值为P1,P2……Pn(Pi为整数)。求背包能够容纳的最大价值。
跟01背包的区别:每种东西有无限个
现实应用
盗墓者 拿了一个背包,体积W一定。墓葬中有不同体积的金块,价值各不一样。盗墓者当然希望尽可能拿走最大价值的金子。
东西编号 : D1 D2 D3 D4
体积W : 2 3 4 5
价值V : 3 4 5 6
背包体积W:8
穷举画图
假设有两个东西:D1 D2,每次选择都有两种选择,直到包里装不下东西(根据体积来算,或者拿不了(根据重量))。
F(W)
D1 D2 ---- 第一次选择
D1 D2 D1 D2 ---- 第二次选择
D1 D2 D1 D2 D1 D2 D1 D2 ---- 第三次选择
……
F(8): 装满体积8的最大价值
D1.W: D1东西的体积
D2.V: D2东西的价值
F(W) = Max( F(W-D1.W) + D1.V,F(W-D2.W)+D2.V )
代码
public class package01 {
@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();
Assert.assertEquals(12, Solution.maxValue01(dongs,w));
}
class Solution {
public int maxValue01(Dong[] dongs,int w) {
if(w <= 0){
return 0;
}
int maxValue = 0;
int tempMaxValue = 0;
for(int i = 0 ; i < dongs.length ; i++,tempMaxValue = 0){
if(dongs[i].w > w){
// 背包装不下:当前东西的体积直接比背包大,装个屁直接忽略
continue;
}else if(dongs[i].w <= w){
/**
* 背包装得下:东西体积跟背包体积一样大,或者小于
* 剩余体积能装最大的价值 + 当前装的东西的价值
* F(W) = Max( F(W-D1.W) + D1.V, F(W-D2.W)+D2.V )
*/
tempMaxValue = maxValue01(dongs , w - dongs[i].w) + dongs[i].v;
}
// 如果这种币值的钱张数 比较少就记录
if(tempMaxValue > maxValue){
maxValue = tempMaxValue;
}
}
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