1. 问题描述
输入: n组输入<vi, wi>(vi, wi > 0)(value 价值, weight 重量), 最大重量 C;
输出: 一组代表选择的序列<x1, x2, …, xn>, 其中 xi ∈ {0, 1}, 即代表选择 / 不选择,使得下面两个条件成立:
Σ
i
=
1
n
w
i
x
i
≤
C
\Sigma_{i = 1}^{n} w_ix_i ≤ C
Σi=1nwixi≤C
m
a
x
Σ
i
=
1
n
v
i
x
i
max\Sigma_{i = 1}^{n} v_ix_i
maxΣi=1nvixi
(下面用这两个方程来代指某个0-1背包问题)
2.问题求解
2.1 最优解的结构
设<x1, x2, …, xn>是 Σ i = 1 n w i x i ≤ C \Sigma_{i = 1}^{n} w_ix_i ≤ C Σi=1nwixi≤C m a x Σ i = 1 n v i x i max\Sigma_{i = 1}^{n} v_ix_i maxΣi=1nvixi的一组最优解,则<x1, x2, …, xn-1>是 Σ i = 1 n − 1 w i x i ≤ C − w n x n \Sigma_{i = 1}^{n - 1} w_ix_i ≤ C - w_nx_n Σi=1n−1wixi≤C−wnxn m a x Σ i = 1 n − 1 v i x i max\Sigma_{i = 1}^{n - 1} v_ix_i maxΣi=1n−1vixi的一组最优解.注意到前后两组方程在最大重量和输入规模上有差异,因此有状态定义如下:
2.2 状态定义及状态转移方程
定义
m
[
i
]
[
w
]
m[i][w]
m[i][w]为限制输入规模在
[
1
,
i
]
[1, i]
[1,i]且限制最大重量为
w
w
w时的最大价值
m
[
1
]
[
w
]
=
0
(
0
≤
w
<
w
1
)
m[1][w] = 0~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0≤w<w_1)
m[1][w]=0 (0≤w<w1)
m
[
1
]
[
w
]
=
v
1
(
w
≥
w
1
)
m[1][w] = v_1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(w≥ w_1)
m[1][w]=v1 (w≥w1)
m
[
i
]
[
w
]
=
m
[
i
−
1
]
[
w
]
(
0
≤
w
<
w
i
)
m[i][w] = m[i - 1][w]~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0≤w<w_i)
m[i][w]=m[i−1][w] (0≤w<wi)
m
[
i
]
[
w
]
=
m
a
x
(
m
[
i
−
1
]
[
w
]
,
m
[
i
−
1
]
[
w
−
w
i
]
+
v
i
)
(
w
≥
w
i
)
m[i][w] = max(m[i - 1][w], m[i - 1][w - w_i] + v_i)~~~~~~(w≥w_i)
m[i][w]=max(m[i−1][w],m[i−1][w−wi]+vi) (w≥wi)
*前两个方程是递归的基础,后两个方程代表了这样一种递归逻辑: 当最大重量足够装下第i个物品时,遍历第i个物品是否被选择,选择其中值较大者.
2.3 计算
略
2.4 构造最优解
m [ n ] [ C ] m[n][C] m[n][C]即为所求
3. 代码
模板题: http://acm.hit.edu.cn/contest/177/problem/E (好像只有我自己能打开, 留给自己复习用吧, 反正也没人看)
#include<stdio.h>
int v[101];
int w[101];
int m[101][10001];
int max(int x, int y) {
return (x > y ? x : y);
}
int main() {
int t, tt;
scanf("%d", &t);
for (tt = 1; tt <= t; tt++) {
int n, c;
scanf("%d %d", &n, &c);
int i, j;
for (i = 1; i <= n; ++i) {
scanf("%d %d", w + i, v + i);
}
for (i = 1; i <= n; ++i) {
for (j = 0; j <= c; ++j) {
if (i == 1 && j < w[i])
m[i][j] = 0;
else if (i == 1 && j >= w[i])
m[i][j] = v[i];
else if (i > 1 && j < w[i])
m[i][j] = m[i - 1][j];
else
m[i][j] = max(m[i - 1][j], m[i - 1][j - w[i]] + v[i]);
}
}
printf("Case #%d: %d\n", tt, m[n][c]);
}
}