1.0-1问题 fractional knapsack
现在有m件物品,小偷有个最大承重为n的背包,单独的一件物品可拆分,求最后的可得的最大重量。
2.首先计算每个商品的单位价值,遵循贪心策略,小偷首先尽量多地拿走单位价值最高的商品,若该商品已经全部拿走而背包未满,将在剩余的商品中选择单位价值最高的拿走,以此类推,若剩余空间不够选择的商品全部拿走,则将剩余空间全部装上该商品的等重部分(即把该商品拿走与背包空间刚好相同的重量)。
Step1:首先计算每件商品的单位价值;
Step2:按照商品的单位价值从高到低排序;
Step3:依次按照单位价值从高到低选择商品,判断当前剩余空间能否全部装下该商品,若能则装下该商品,剩余空间减去该商品的空间,继续循环Step3,若不能,则把剩余空间装下该商品的等重部分,算法结束。
背包内物品的类:额外设计一个表示背包内物品的类是为了计算方便,并且在算法结束后可以知道每件物品往背包内所放的重量。
class Item implements Comparable<Item> { public String name;// 物品的名字 public int weight;// 物品的重量 public int value;// 物品的价值 public double price;// 单位价值 public double inputWeight;// 被放到背包中的重量 public Item(String name, int weight, int value) { this.name = name; this.weight = weight; this.value = value; this.price = value/weight; } public int compareTo(Item vo) { return this.price >= vo.price ? -1 : 1; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getWeight() { return weight; } public void setWeight(int weight) { this.weight = weight; } public int getValue() { return value; } public void setValue(int value) { this.value = value; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public double getInputWeight() { return inputWeight; } public void setInputWeight(double inputWeight) { this.inputWeight = inputWeight; } }
/** * 解决0--1分数背包问题。 * * @param list * 传进来的是m件物品 * @param m * 背包的最大重量 * @return 背包内所装物品的最大价值。 */ public double fractionalKnapsack(ArrayList<Item> list,int m){ double result = 0;//最后返回的价值 /*首先计算每件商品的单位价值,按照商品的单位价值从高到低排序*/ Collections.sort(list); int size = list.size(); for(int i =0;i<size;i++){ Item vo = list.get(i); if(m>=vo.getWeight()){//说明当前商品可以全部放进去 m = m-vo.getWeight(); result = result + vo.getValue(); vo.setInputWeight(vo.getWeight());//设置该商品放到背包中的重量 }else if(m>0){//可放到背包的最后一件商品需要拆分 vo.setInputWeight(m); result = result + m*vo.getPrice(); m = 0; }else{ break; } } return result; }
public static void main(String[] args){ FractionalKnapsack test = new FractionalKnapsack(); Item B0 = new Item("F",5,6); Item B1 = new Item("D",4,6); Item B2 = new Item("C",1,6); Item B3 = new Item("B",2,6); Item B4 = new Item("A",3,6); ArrayList<Item> list = new ArrayList<Item>(); list.add(B0); list.add(B1); list.add(B2); list.add(B3); list.add(B4); /*求往背包承重为10的背包内可装的物品的最大价值*/ double re = test.fractionalKnapsack(list, 10); System.out.println("往背包承重为10的背包内可装的物品的最大价值 re = "+re); System.out.println("依次选择的物品名称与放到背包内的重量"); for(int i =0;i<list.size();i++){ Item vo = list.get(i); System.out.println(vo.getName()+" "+vo.getInputWeight()); } }