1、小数背包问题
n种物品,1个背包,背包可容纳的总重量为c,每个物品i的价值为vi,重量为wi,如何选择物品,使得装入物品的总价值最大?这个是小数背包问题,不同于0-1背包问题,0-1背包问题中,整个物品不可分割,要么不装入要么全部装入。
2、贪心策略
将物品按照性价比(单位重量价值)进行从大到小排序,将尽可能多的高性价比的物品装入背包,若将这种物品全部装入背包后,背包还有多余容量,则选择单位重量价值次高的并尽可能多地装入背包。如果最后一件物品无法全部装入,则计算可以装入的比例,然后按比例装入。
3、实战代码
(1)题目描述:
设有5个物品,每个商品的价值分别是4, 6, 3, 5, 6,每个商品的重量分别是5, 4, 2, 6, 2,背包的总容量是10,求装包方案使得包中的商品价值最大。
(2)分析:
需要定义一个类,类中封装物品编号num、商品价值value和商品重量weight,同时要定义排序规则。为什么要建个类呢?因为要对性价比排序,排序后各个物品的位置会发生变化,为了容易找到排序前的原始编号,所以定义了一个类,在类中封装了物品原始编号,使得不论怎么排序,原始编号都和对应的value、weight和性价比绑定。当然,乍一想感觉使用hashmap也可以实现排序后编号和性价比的绑定,把性价比当做map中的键key,编号作为map中的值,但是可能会出现相同性价比的问题,所以出现冲突时不宜区分。此处采用定义类的方式
import java.util.*;
public class Main {
public static void main(String[] args) {
// 因为性价比要作商,所以此处定义为double类型
double[] value={4, 6, 3, 5, 6};
double[] weight={5, 4, 2, 6, 2};
double c = 10;
int n = 5;
List<Good> list = new ArrayList<>();
for(int i = 0; i < n; i++){
Good act = new Good(i+1,value[i],weight[i],value[i]/weight[i]);
list.add(act);
}
//自定义排序规则,按照性价比从高到低排序
Collections.sort(list, new Comparator<Good>() {
// 此方法的返回值为int,但是性价比做差为double
// 此处根据double的正负来返回1,-1和0
@Override
public int compare(Good o1, Good o2) {
int result = 0;
if(o2.getValueByWeight() - o1.getValueByWeight() > 0){
result = 1;
}else if(o2.getValueByWeight() - o1.getValueByWeight() < 0){
result = -1;
}
return result;
}
});
// 由于我想最终返回选择的物品编号和该物品的重量,所以此处定义了二维的list
ArrayList<ArrayList<Double>> result = new ArrayList<ArrayList<Double>>();
double currentWeight = 0;
int index = 0;
while(currentWeight < c && index < n){
// 此物品可以完整的放入包中
if(list.get(index).getWeight() + currentWeight <= c){
ArrayList<Double> tem = new ArrayList<Double>();
tem.add((double)list.get(index).getNum());
tem.add(list.get(index).getWeight());
result.add(tem);
// 更新放入包中的总重量
currentWeight+=list.get(index).getWeight();
index++;
}else{
break;
}
}
// 处理最优一个物品,最后一个物品可能不能完全放入包中,单独处理
ArrayList<Double> last = new ArrayList<Double>();
last.add((double)list.get(index).getNum());
last.add((c - currentWeight));
result.add(last);
// 打印结果,由于result定义为double类型,导致打印的编号出现小数点,此处用了字符串截取
for(ArrayList<Double> fac : result){
System.out.println("所选物品是"+fac.get(0).toString().substring(0,1)+"--选择了"+fac.get(1));
}
}
}
class Good{
int num;
// 因为性价比要作商,所以此处定义为double类型
double value;
double weight;
double valueByWeight;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public double getValue() {
return value;
}
public void setValue(double value) {
this.value = value;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double getValueByWeight() {
return valueByWeight;
}
public void setValueByWeight(double valueByWeight) {
this.valueByWeight = valueByWeight;
}
public Good(int num, double value, double weight, double valueByWeight) {
this.num = num;
this.value = value;
this.weight = weight;
this.valueByWeight = valueByWeight;
}
}
运算结果: