贪心算法之背包问题
背包问题是算法的经典问题,分为部分背包和0-1背包,主要区别如下:
部分背包:某件物品是一堆,可以带走其一部分
0-1背包:对于某件物品,要么被带走(选择了它),要么不被带走(没有选择它),不存在只带走一部分的情况。
部分背包问题
假设一共有N件物品,第 i 件物品的价值为 Vi ,重量为Wi,一个小偷有一个最多只能装下重量为W的背包,他希望带走的物品越有价值越好,可以带走某件物品的一部分,请问:他应该选择哪些物品?
假设背包可容纳50Kg的重量,物品信息如下表:
将物品按单位重量 所具有的价值排序。总是优先选择单位重量下价值最大的物品,单位重量的价值排序:物品A > 物品B > 物品C
因此,我们尽可能地多拿物品A,直到将物品1拿完之后,才去拿物品B,然后是物品C 可以只拿一部分…..
public class Bag {
/**
* 最大承重
*/
private double max=0;
private void getMaxValue(Goods[] goodsList){
// 对物品按照价值排序从高到低
Arrays.sort(goodsList, Comparator.comparingDouble((Goods goods) -> goods.value).reversed());
//当前总重
double sumWeight=0;
// 取出价值最高的
for(int i=0;i<goodsList.length;i++){
sumWeight+=goodsList[i].weight;
if(sumWeight<=max){
System.out.println(goodsList[i].name+"取"+goodsList[i].weight+"kg");
}
else{
System.out.println(goodsList[i].name+"取"+(max-(sumWeight-goodsList[i].weight))+"kg");
return ;
}
}
}
public static void main(String[] args) {
Bag bag=new Bag();
Goods g1=new Goods("A",10,60);
Goods g2=new Goods("B",20,100);
Goods g3=new Goods("C",30,120);
Goods[] goods={g1,g2,g3};
bag.max=50;
bag.getMaxValue(goods);
}
}
public class Goods {
/**
* 名称
*/
String name;
/**
* 重量
*/
double weight;
/**
* 价格
*/
double price;
/**
* 价值
*/
double value;
public Goods(String name, double weight, double price) {
this.name = name;
this.weight = weight;
this.price = price;
this.value=price/weight;
}
}
0-1背包问题
有n件物品和一个最大承重为W的背包,每件物品的重量是w[i],价值是v[i],在保证总重量不超过W的前提下,选择某些物品装入背包,背包的最大总价值是多少?
注意:每个物品只有一件,也就是每个物品只能选择0件或者1件
分析:
假设:W=10,有5件物品,重量和价值如下:
w[1]=2,v[1]=6
w[2]=2,v[2]=3
w[3]=6,v[3]=5
w[4]=5,v[4]=4
w[5]=4,v[5]=6
dp数组的计算结果如下表:
i:选择i件物品 j:最大承重public class Bag01 {
public static int maxValue(int[] values, int[] weights, int max){
if(values == null || values.length == 0){
return 0;
}
if(weights == null || weights.length == 0){
return 0;
}
if(max <= 0){
return 0;
}
int dp[][] = new int[values.length+1][max+1];
for (int i = 1; i <= values.length; i++) {
for (int j = 1; j <= max; j++) {
// 选中的物品重量
int selectedWeight = weights[i - 1];
// 如果选择的物品重量超过最大承重
if(selectedWeight > j){
// 最大的价值 = 上一轮的最大价值(不选择该物品)
dp[i][j] = dp[i-1][j];
}else {
// 选择物品
// 选择该物品之后的价值 与 不选择该物品的价值(上一轮的最大价值)做比较,找出最大值
dp[i][j] = Math.max(dp[i-1][j],values[i-1]+dp[i-1][weights[i-1]]);
}
}
}
return dp[values.length][max];
}
public static void main(String[] args) {
int[] values={6,3,5,4,6};
int[] weights={2,2,6,5,4};
int max = 10;
System.out.println(maxValue(values,weights,max));
}
}