POJ 3466 带限制的 0 1背包问题
分析如下:
由于必须要 超过 q 值才能购买,而无论是一维还是二维普通
0
0
0
1
1
1 背包问题,它后一个的值都需要用到上一个的值。
比如:
我们现在更新
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j],需要用到
d
p
[
i
−
1
]
[
j
−
w
[
i
]
]
+
v
[
i
]
dp[i-1][j-w[i]]+v[i]
dp[i−1][j−w[i]]+v[i] 的值,但是必须满足的是,当前
j
j
j 要大于给定的
q
[
i
]
q[i]
q[i]才能转移,所以如果以
d
p
[
i
−
1
]
[
j
−
w
[
i
]
]
+
v
[
i
]
dp[i-1][j-w[i]]+v[i]
dp[i−1][j−w[i]]+v[i] 来更新
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 的话,那么 j 必须要 大于等于 p 才可以。
那么更新
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] ,我需要的是
d
p
[
i
−
1
]
[
p
2
−
w
[
i
]
]
+
v
[
i
]
到
d
p
[
i
−
1
]
[
V
−
w
[
i
]
]
+
v
[
i
]
①
dp[i-1][p2-w[i]]+v[i] 到 dp[i-1][V-w[i]]+v[i] ①
dp[i−1][p2−w[i]]+v[i]到dp[i−1][V−w[i]]+v[i]① 的值。(
P
2
P2
P2 指的是 第
i
i
i 物品的
p
p
p 值)
而对于第
i
−
1
i-1
i−1 的物品,我只有当
j
>
=
p
1
j>=p1
j>=p1 的时候,
d
p
[
i
−
1
]
[
j
−
w
[
i
]
]
+
v
[
i
]
②
dp[i-1][j-w[i]]+v[i]②
dp[i−1][j−w[i]]+v[i]② 才更新,即我只更新了
d
p
[
i
−
1
]
[
p
1
−
w
[
i
]
]
+
v
[
i
]
到
d
p
[
i
−
1
]
[
V
−
w
[
i
]
]
+
v
[
i
]
dp[i-1][p1-w[i]]+v[i] 到 dp[i-1][V-w[i]]+v[i]
dp[i−1][p1−w[i]]+v[i]到dp[i−1][V−w[i]]+v[i]的值。
所以如果我要更新
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j],那么必须要使得
②
②
②的范围包含
①
①
①的范围,故需要
p
1
−
q
1
>
p
2
−
q
2
p1-q1>p2-q2
p1−q1>p2−q2 ,所以进行
D
P
DP
DP之前,需要先以
(
p
−
q
)
(p-q)
(p−q)降序排列,再进行 普通
01
0 1
01 背包即可。
代码如下:
#include<iostream>
#include<algorithm>
#include<string.h>
#define MAXN 508
using namespace std;
int n, m;
int dp[5008];
struct Node
{
int p;
int q;
int v;
}A[MAXN];
bool cmp(const Node a, const Node b) {
return a.q - a.p < b.q - b.p;
}
int main()
{
while (~scanf_s("%d%d", &n, &m))
{
for (int i = 1; i <= n; i++) {
scanf_s("%d%d%d", &A[i].p, &A[i].q, &A[i].v);
}
memset(dp, 0, sizeof(dp));
sort(A + 1, A + n + 1, cmp);
for (int i = 1; i <= n; i++) {
for (int j = m; j >= A[i].q; j--) {
dp[j] = max(dp[j], dp[j - A[i].p] + A[i].v);
}
}
printf("%d\n", dp[m]);
}
}