算法设计实验四
实验四 0-1背包问题
问题描述
给定 n 个物品,物品 i 的重量是w[i], 其价值为v[i],背包容量为 c,问如何选择装入背包中的物品,使得装入背包中的物品其总价值最大?
求解方法
设 m(n, c) 表示当物品个数为 n,背包容量为 c 时的最优值,即可选的物品为0, 1, 2, ..., n-1, 则可得递归式如下:
当 w[n-1] > c 时,
m(n, c) = m(n-1, c);
否则:
m(n, c) = Max{ m(n-1, c), m(n-1, c - w[n-1]) + v[n-1] }
其中,Max{a, b} 表示取 a,b 的最大值。
参考实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 3 // 物品个数
#define CAPACITY 10 // 最大容量限制
int weights[N]; // 重量
int prices[N]; // 价值
int maxPriceInBag(int n, int capacity) {
if (n == 1) {
if (weights[0] <= capacity)
return prices[0];
else
return 0;
}
if (weights[n-1] > capacity) {
return maxPriceInBag(n-1, capacity);
} else {
// 没有选择最后一个物品时的值
int v1 = maxPriceInBag(n-1, capacity);
// 选择最后一个物品时的值
int v2 = maxPriceInBag(n-1, capacity - weights[n-1]) + prices[n-1];
// 两个值中取最大的
return v1 > v2 ? v1 : v2;
}
}
void initGoods();
void printGoods();
int main() {
int result;
initGoods();
printGoods();
result = maxPriceInBag(N, CAPACITY);
printf("\nresult = %d\n", result);
return 0;
}
// 产生一个随机值,该值位于 [down, up) 内.
unsigned randValue(unsigned down, unsigned up) {
unsigned range = up - down;
return rand() % range + down;
}
// 初始化物品
void initGoods() {
int i;
srand(time(0));
for (i = 0; i < N; ++i) {
weights[i] = randValue(1, 10);
prices[i] = randValue(1, 100);
}
}
// 打印物品
void printGoods() {
int i;
puts("\n");
for (i = 0; i < N; ++i) {
printf("%d: weight = %d \t price = %d\n", i, weights[i], prices[i]);
}
}
穷举法求解
设共3个物品,1 表示该物品放放背包内,0 表示没有放入,则
001 表示了一种选择,即第3个物品放入,其它没有。
则下一个选择分别是 010,011,100,101,110,111
当出现 111(即全1)时,穷举结束。
参考实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 3
#define CAPACITY 10
int weights[N]; // 重量
int prices[N]; // 价值
int selected[N]; // 是否选中,1:选中, 0:没有。
// 枚举下一个选择组合,如果所有的情况都已穷举完,返回0.
// 如 010 下一个就是 011,接下来是 100,101, 110, 111
// 实现时采用末端加 1,依此向前进位。
int next() {
int i;
for(i = 0; i < N; i++) {
if (selected[i] == 0) {
selected[i] = 1;
return 1;
} else {
selected[i] = 0;
}
}
return 0;
}
// 根据 selected 将数组 a 相加,没有选中的不计入内
int sum(int *a) {
int i, s = 0;
for(i = 0; i < N; i++) {
if (selected[i]) {
s += a[i];
}
}
return s;
}
int maxPriceInBag() {
int i, maxPrice = 0;
while (next()) {
if (sum(weights) <= CAPACITY) {
int price = sum(prices);
if (maxPrice < price) maxPrice = price;
}
}
return maxPrice;
}
void initGoods();
void printGoods();
int main() {
initGoods();
printGoods();
int result = maxPriceInBag();
printf("\nresult = %d\n", result);
return 0;
}
// 产生一个随机值,该值位于 [down, up) 内.
unsigned randValue(unsigned down, unsigned up) {
unsigned range = up - down;
return rand() % range + down;
}
void initGoods() {
int i;
srand(time(0));
for (i = 0; i < N; ++i) {
weights[i] = randValue(1, 10);
prices[i] = randValue(1, 100);
}
}
void printGoods() {
int i;
puts("\n");
for (i = 0; i < N; ++i) {
printf("%d: weight = %d \t price = %d\n", i, weights[i], prices[i]);
}
}
思考与练习
- 要使装入背包中的物品其总价值最大,要选择哪些物品? 试修改程序以打印出选择结果。
浙公网安备 33010602011771号