分数背包问题(Fractional Knapsack Problem)是一种经典的组合优化问题,它描述了如何从一组物品中选择部分物品装入背包,以使得装入背包的物品总价值最大。与 0/1 背包问题不同,分数背包问题允许将物品分割为更小的部分,以便更好地利用背包的容量。
问题描述如下:
给定一组物品,每个物品都有一个重量(weight)和一个价值(value)。同时给定一个背包的容量(capacity)。目标是选择一些物品,使得它们的总重量不超过背包的容量,且总价值最大。
分数背包问题的解决方法通常涉及贪心算法。以下是一种基本的贪心策略:
- 计算每个物品的单位价值:将每个物品的价值除以其重量,得到单位重量的价值。
- 按照单位价值排序:将物品按照单位价值降序排列,这样在贪心选择时可以优先选择单位价值最高的物品。
- 贪心选择:从单位价值最高的物品开始,依次将物品加入背包,直到背包装满。
这种贪心策略的正确性证明并不难,它基于这样的观察:在有限容量的背包中,优先选择单位价值最高的物品是最优解的一部分。如果采用其他策略,可能会导致浪费背包容量,从而得到的解不是最优的。
/**
* 1.n个物品都是液体,有重量和价值
* 2.现在你要取走 10升 的液体
* 3。每次可以不拿,全拿,或拿一部分,问最高价值是多少
*
* 编号 重量(升) 价值
* 0 4 24 水
* 1 8 160 牛奶
* 2 2 4000 五粮液
* 3 6 108 可乐
* 4 1 4000 茅台
*/
public class FractionalKnapsackProblem {
static class Item {
int index;
int weight;
int value;
public Item(int index, int weight, int value) {
this.index = index;
this.weight = weight;
this.value = value;
}
public int unitValue() {
return value / weight;
}
@Override
public String toString() {
return "Item(" +
"index=" + index +
')';
}
}
public static void main(String[] args) {
Item[] items = new Item[]{
new Item(0, 4, 24),
new Item(1, 8, 160),
new Item(2, 2, 4000),
new Item(3, 6, 108),
new Item(4, 1, 4000),
};
select(items, 10);
}
static void select(Item[] items, int total) {
Arrays.sort(items, Comparator.comparingInt(Item::unitValue).reversed());
int max = 0; //最大价值
for (Item item : items) {
System.out.println(item);
if (total >= item.weight) {//可以拿完
total -= item.weight;
max += item.value;
} else { //拿不完
max += total * item.unitValue();
break;
}
}
System.out.println("最大价值是:"+max);
}
}