问题:现有四个物品,小偷背包总容量为8,怎么可以偷得价值最多的物品?
物品编号:1 2 3 4
物品重量:2 3 4 5
物品价值:3 4 5 8
记f(k, w):当背包容量为w,现有k件物品可以偷,所能得到的最大价值。
#include <stdio.h>
int f[5][9] = {0};
int w[5] = {0, 2, 3, 4, 5}; /* 物品重量 */
int v[5] = {0, 3, 4, 5, 8}; /* 物品价值 */
int main (void)
{
int i, j;
int buf[5] = {0};
memset(f, 0, sizeof(f));
for (i = 1; i < 5; i++) {
for (j = 1; j < 9; j++) {
if (w[i] > j) {
/* 如果w[i]重量比剩余重量大,则i号物品不能装入 */
f[i][j] = f[i-1][j];
} else {
/* 如果w[i]重量比剩余重量小,则i号物品可以装入,但分装与不装两种情况 */
/* 装入时总价值为:f[i-1][j-w[i]] + v[i] */
/* 不装时总价值为:f[i-1][j] */
/* 两种情况的总价值大小比较,采用大的那种方式装包 */
if (f[i-1][j-w[i]] + v[i] > f[i-1][j]) {
f[i][j] = f[i-1][j-w[i]] + v[i];
} else {
f[i][j] = f[i-1][j];
}
}
printf("%2d ", f[i][j]);
}
printf("\n");
}
printf("最佳策略:\n");
i = 4;
j = 8;
while (i != 0 && j != 0) {
if (f[i][j] > f[i-1][j]) {
printf("%d\n", i);
j = j-w[i];
i = i-1;
} else {
i = i-1;
}
}
return 0;
}
运行结果:
若原问题增加条件:如果装了物品2,则一定要装物品1,装了物品1,不一定要装物品2
则需要这样修改代码:
#include <stdio.h>
int f[5][9] = {0};
int w[5] = {0, 2, 3, 4, 5}; /* 物品重量 */
int v[5] = {0, 3, 4, 5, 8}; /* 物品价值 */
int main (void)
{
int i, j;
int buf[5] = {0};
memset(f, 0, sizeof(f));
for (i = 1; i < 5; i++) {
for (j = 1; j < 9; j++) {
if (w[i] > j) {
/* 如果w[i]重量比剩余重量大,则i号物品不能装入 */
f[i][j] = f[i-1][j];
} else {
/* 如果w[i]重量比剩余重量小,则i号物品可以装入,但分装与不装两种情况 */
/* 装入时总价值为:f[i-1][j-w[i]] + v[i] */
/* 不装时总价值为:f[i-1][j] */
/* 两种情况的总价值大小比较,采用大的那种方式装包 */
if (f[i-1][j-w[i]] + v[i] > f[i-1][j]) {
/*
* 若增加条件:如果装了物品2,则一定要装物品1,装了物品1,不一定要装物品2
* 则需要增加以下if判断,实现:如果当前剩余重量装了物品2后,就得拿出物品1,
* 那么即使物品2代替物品1可以增大总价值,仍然不去这么做。
*/
if (i == 2 && f[i-1][j-w[i]] == 0) {
f[i][j] = f[i-1][j];
} else {
f[i][j] = f[i-1][j-w[i]] + v[i];
}
} else {
f[i][j] = f[i-1][j];
}
}
printf("%2d ", f[i][j]);
}
printf("\n");
}
printf("最佳策略:\n");
i = 4;
j = 8;
while (i != 0 && j != 0) {
if (f[i][j] > f[i-1][j]) {
printf("%d\n", i);
j = j-w[i];
i = i-1;
} else {
i = i-1;
}
}
return 0;
}
运行结果: