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;
}
例如求解某五件商品在背包承重为10 的时候可装的最大价值。
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());
}
}