赞
踩
背包的最大容量为 6 6 6。
物品 | 体积 v v v | 价值 w w w |
---|---|---|
A A A | 2 2 2 | 3 3 3 |
B B B | 3 3 3 | 5 5 5 |
C C C | 4 4 4 | 6 6 6 |
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | ||||||
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | ||||||
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 |
⇓
\Downarrow
⇓
∙
\bullet
∙对于每一个单元格
i
.
w
e
i
g
h
t
>
j
i.weight>j
i.weight>j是否成立,按行填写
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | ||||||
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 |
⇓ \Downarrow ⇓
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | 0 | 3 | 5 | 5 | 8 | 8 |
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 |
⇓ \Downarrow ⇓
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | 0 | 3 | 5 | 5 | 8 | 8 |
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 | 0 | 3 | 5 | 6 | 8 | 9 |
滚动dp一维数组版
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
0 0 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
⇓ \Downarrow ⇓
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
1 1 1 A ( 2 , 3 ) A(2,3) A(2,3) | 0 | 0 | 3 | 3 | 3 | 3 | 3 |
⇓ \Downarrow ⇓
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
2 2 2 B ( 3 , 5 ) B(3,5) B(3,5) | 0 | 0 | 3 | 5 | 5 | 8 | 8 |
⇓ \Downarrow ⇓
0 0 0 | 1 1 1 | 2 2 2 | 3 3 3 | 4 4 4 | 5 5 5 | 6 6 6 | |
---|---|---|---|---|---|---|---|
3 3 3 C ( 4 , 6 ) C(4,6) C(4,6) | 0 | 0 | 3 | 5 | 6 | 8 | 9 |
有
n
n
n件物品,每件物品的重量为
w
[
i
]
w[i]
w[i],价值为
c
[
i
]
c[i]
c[i]。现有一个容量为
V
V
V,的背包,问如何选取物品放入背包,使得背包物品的总价值最大。其中每件物品有无穷件。
既然这样,不妨像0-1背包问题那样,先写出状态转移方程,从源头上摸索。
d
p
{
状态表示
(
i
,
j
)
{
集合:所有只从前
i
个物品中选,总体积不超过
j
的方案的集合
属性:
m
a
x
状态计算
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
f
[
i
−
1
]
[
j
−
v
]
+
w
、
f
[
i
−
1
]
[
j
−
2
v
]
+
2
w
、
.
.
.
.
.
.
)
,
d
p
[
i
]
[
j
−
v
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
−
v
]
,
f
[
i
−
1
]
[
j
−
2
v
]
+
w
、
f
[
i
−
1
]
[
j
−
3
v
]
+
2
w
、
.
.
.
.
.
.
)
+
w
,两式组合
d
p
[
i
]
[
j
]
=
m
a
x
(
d
p
[
i
−
1
]
[
j
]
,
f
[
i
]
[
j
−
v
]
+
w
)
如下图选第
i
个物品
dp
例如:
容量j | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
组号 | 物品 | 体积v | 价值w | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | (无) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 小古银手办 | 2 | 1 | 0 | 0 | 1 | 1 | 2 | 2 | 3 | 3 |
2 | 平板电脑 | 3 | 3 | 0 | 0 | 1 | 3 | 3 | 4 | 6 | 6 |
3 | 笔记本电脑 | 4 | 5 | 0 | 0 | 1 | 3 | 5 | 5 | 6 | 8 |
4 | 无价之宝 | 5 | 0 | 0 | 0 | 1 | 3 | 5 | 5 | 6 | 8 |
规律:
∙
\bullet
∙当
j
<
v
i
j<v_i
j<vi的时候,
w
i
,
j
=
w
i
−
1
,
j
w_{i,j}=w_{i-1,j}
wi,j=wi−1,j(解释:如果当前物品装不进背包,最大价值和前
i
−
1
i-1
i−1个物品的最大价值一样)
∙
\bullet
∙当
j
≥
v
i
j\ge v_i
j≥vi的时候,
w
i
,
j
=
m
a
x
(
w
i
−
1
,
j
w_{i,j}=max(w_{i-1,j}
wi,j=max(wi−1,j不装,装
)
)
)(解释:如果装的下,在装和不装中选最大价值)
int m = 0; int n = 0; cin >> m >> n; int v[40] = {}; int w[40] = {}; for (int i = 1; i <= n; i ++){ cin >> v[i] >> w[i]; } int dp[40][210] = {}; for (int i = 1; i <= n; ++ i) { for (int j = 1; j <= m; ++ j) { if (j < v[i]) { dp[i][j] = dp[i - 1][j]; } else { dp[i][j] = max(dp[i - 1][j], dp[i][j - v[i]] + w[i]) } } } cout << "max = " << dp[n][m] <<endl;
优化版代码:
int m = 0;
int n = 0;
cin >> m >> n;
int v[40] = {};
int w[40] = {};
for (int i = 1; i <= n; i ++){
cin >> v[i] >> w[i];
}
int dp[40][210] = {};
for (int i = 1; i <= n; ++ i) {
for (int j = v[i]; j <= m; ++ j) {
dp[j] = max(dp[j], dp[j - v[i]] + w[i])
}
}
cout << "max = " << dp[n][m] <<endl;
求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大,但要注意的是,每件要取物品不能超过他给出的最大数量。
for(int i = 0; i < n; i ++)
for(int j = m; j >= v[i]; j --)
dp[j] = max(dp[j], dp[j - v[i]] + w[i], dp[j - 2 * v[i]] + 2 * w[i],......)//每件物品可以不去,可以取1个,或者取2个等等。
假设有一种物品有 s s s 件,若要将其拆分开来,则从 1 1 1 开始循环,每进行一次循环就乘 2 2 2,并每循环一次就减去迭代的变量 i i i,代码如下:
while (n--) {
int v, w, s;
scanf("%d%d%d", &v, &w, &s);
for (int i = 1; i <= s; i *= 2) {
s -= i;
goods.push_back({ v * i,w * i });
}
if (s > 0)goods.push_back({ v * s,w * s });
}
有 N N N组物品和一个容量是 V V V的背包。每组物品有若干个,同一组内的物品最多只能选一个。每件物品的体积是 v i j v_{ij} vij,价值是 w i j w_{ij} wij,其中 i i i是组号, j j j是组内编号。
例如:
∙
\bullet
∙一个组只能选一个物品
组号 | 物品 | 体积v | 价值w |
---|---|---|---|
1 | 小古银手办 | 2 | 1 |
平板电脑 | 3 | 3 | |
2 | 笔记本电脑 | 4 | 5 |
3 | 无价之宝 | 5 | 0 |
以下是动态模拟:
∙
\bullet
∙每个组都有装和不装两种情况
∙
\bullet
∙如果装某个组的话,这个组只能装一次
容量j | ||||||||
---|---|---|---|---|---|---|---|---|
组号 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | |||||||
2 | 0 | |||||||
3 | 0 |
#include<iostream> #include<algorithm> using namespace std; const int N = 110; int n, m; int v[N], w[N], dp[N]; int main() { scanf("%d%d", &n, &m); while (n--) { int s; scanf("%d", &s); for (int i = 0; i < s; i++) scanf("%d%d", &v[i], &w[i]); for (int j = m; j >= 0; j--) { for (int k = 0; k < s; k++) { if (j >= v[k]) { dp[j] = max(dp[j], dp[j - v[k]] + w[k]); } } } } printf("%d", dp[m]); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。