您的位置:首页 > 其它

01 背包

2016-05-19 18:52 232 查看

01背包

问题描述:给定 n 种物品和一背包,物品 i 的重量是 wi,其价值是 vi,背包容量为 c,问应如何选择装入背包中的物品,使装入背包中的物品价值最大?

回溯法

在搜索解空间树时,只要其左儿子节点是一个可行节点,搜索就进入其左子树。当右子树中可能包含最优解时才进入右子树搜索。设 r 是当前剩余物品的价值总和;cv 是当前价值;max 是当前最优价值。当 cv + r <= max 时, 可减去右子树。

void BackTrack(int cw, int cv, int i) {
if (i > n) {
max = cv;
return;
}

if (cw + w[i] <= c)
BackTrack(cw + w[i], cv + v[i], i + 1);
if (cv + r[i + 1]  >  max)
BackTrack(cw, cv, i + 1);
}

void Init() {
for (int i = n; i >= 1; i--)
r[i] = r[i + 1] + v[i];
}


动态规划(递推法)

正常的状态定义
d(i,j) = max{d(i+1,j), d(i+1,j-W[i]) + V[i]}


d(i,j) 表示当前在第 i 层,背包剩余容量为 j 时的最大价值和,边界是 i > n 时 d(i,j) = 0;

for (int i = n; i >= 1; i--)
for (int j = 0; j <= c; j++) {
d[i][j] = (i == n ? 0 : d[i+1][j]);
if (j >= W[i])
d[i][j] = max(d[i][j], d[i+1][j-W[i]] + V[i]);
}


对称的状态定义
f(i,j) = max{f(i-1,j), f(i-1,j-W[i]) + V[i]}


f(i,j) 表示把前 i 个物品装到容量为 j 的背包中的最大价值和,边界是 i= 0 时 f(i,j) = 0;

for (int i = 1; i <= n; i++)
for (int j = 0; j <= c; j++) {
f[i][j] = (i == 1 ? 0 : f[i-1][j]);
if (j >= W[i])
f[i][j] = max(f[i][j], f[i-1][j-W[i]] + V[i]);
}


边读边计算, 不必把 V 和 W 保存下来

for (int i = 1; i <= n; i++) {
scanf("%d%d", &V, &W);
for (int j = 0; j <= c; j++) {
f[i][j] = (i == 1 ? 0 : f[i-1][j]);
if (j >= W)
f[i][j] = max(f[i][j], f[i-1][j-W] + V);
}
}


滚动数组, 把数组 f 变成一维的

memset(f, 0,  sizeof(f));
for (int i = 1; i <= n; i++) {
scanf("%d%d", &V, &W);
for (int j = 0; j <= c; j++)
if (j >= W)
f[j] = max(f[j], f[j-W] + V);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: