部分背包(Fractional Knapsack)
假设有一个小偷,背着一个容量为c的背包(最多可以放的物品重量不能超过c)。商店中一共有n种物品,每种物品i的重量和价值分别为和。如何选择物品放入背包才能使得总价值最大?
假设背包的容量为30,各类物品对应的重量和价格如下:
| 物品 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 重量w | 10 | 5 | 15 | 10 | 20 |
| 价值v | 20 | 30 | 15 | 25 | 10 |
对于部分背包问题,它满足最优子结构性质,因为选定一部分物品后,剩余容量与剩余物品构成的子问题仍需取得最优解。如果要使最终的价值最大,那么必定需要使得选择的单位重量的物品的价值最大。所以背包问题的贪心策略是优先选择单位重量价值最大的物品,当这个物品选择完之后,继续选择其它价值最大的物品。
部分背包
互动实验
部分背包:排序、装入与切分
访问权限PRO
PRO EXCLUSIVE探索不止于此
尊享 Pro 权益解锁完整互动实验、进阶解析与精选参考答案。
C
#include <stdio.h>
#include <stdlib.h>
typedef struct {
double weight;
double value;
double unit_value;
} Item;
Item item_create(double weight, double value) {
Item item;
item.weight = weight;
item.value = value;
item.unit_value = value / weight;
return item;
}
static int cmp(const void *obj1, const void *obj2) {
Item *item1 = (Item *)obj1;
Item *item2 = (Item *)obj2;
if (item1->unit_value > item2->unit_value) {
return -1;
} else if (item1->unit_value < item2->unit_value) {
return 1;
} else {
return 0;
}
}
int knapsack(Item *items, int item_num, int capacity, Item *selected_items) {
qsort(items, item_num, sizeof(Item), cmp);
int selected_num = 0;
double selected_weight = 0;
for (int i = 0; i < item_num; i++) {
if (selected_weight >= capacity) {
break;
}
if (selected_weight + items[i].weight <= capacity) {
selected_weight += items[i].weight;
selected_items[selected_num] = items[i];
selected_num++;
} else {
double portion = (capacity - selected_weight) / items[i].weight;
items[i].weight *= portion;
items[i].value *= portion;
selected_items[selected_num] = items[i];
selected_num++;
break;
}
}
return selected_num;
}
int main(void) {
Item items[] = {
item_create(10, 20),
item_create(5, 30),
item_create(15, 15),
item_create(10, 25),
item_create(20, 10),
};
int item_num = sizeof(items) / sizeof(items[0]);
int capacity = 30;
Item selected_items[item_num];
int selected_num = knapsack(items, item_num, capacity, selected_items);
for (int i = 0; i < selected_num; i++) {
printf("Item(weight=%.2f, value=%.2f, unit_value=%.2f)\n",
selected_items[i].weight,
selected_items[i].value,
selected_items[i].unit_value);
}
return 0;
}知识测验
题目
部分背包为什么可以按单位重量价值选择?
知识测验
题目
物品重10、值25,只能再放4,取部分后增加多少价值?
动手练习
切分最后一件物品
物品 1
w=4, v=20
v/w=5
0%物品 2
w=8, v=24
v/w=3
0%物品 3
w=10, v=20
v/w=2
0%背包容量: 0 / 16
容量16,物品可以拆分。计算单位价值,给出装入顺序、每件所取比例和总价值,并说明最后一件的重量与价值如何同时缩放。