看到这就应该懂了,考虑递归的话要利用之前的经验。那么 f(i,j) 由于体积的限制,当我要取第 i 的时候,可以分为由于装不下第 i 个物品而不取第 i 个和满足体积要求取第 i 个。不取第 i 个的值为 f(i−1,j),取第 i 个的话那么体积要减少价值会增加,其值为 f(i−1,j−v)+w。
f(i,j)=max(f(i−1,j),f(i−1,j−vi)+wi)
二维空间代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v[N],w[N];
int dp[N][N];
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> v[i] >> w[i];
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++){
dp[i][j] = dp[i - 1][j];
if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i - 1][j - v[i]] + w[i]);
}
cout << dp[n][m];
}
其实还可以进行降维优化,由于更新第 i 层时只用了第 i−1 并且更新每个 j 时用到的数据都是之前的数据,可以利用滚动数组来优化。
一维空间代码:
此时的状态数组的含义变为了在 i 体积下,物品的最大值为多少。
// input
// 4 5
// 1 2
// 2 4
// 3 4
// 4 5
// output
// state update
// 0 2 2 2 2 2
// 0 2 4 6 6 6
// 0 2 4 6 6 8
// 0 2 4 6 6 8
// 8
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v[N],w[N];
int dp[N]; //
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> v[i] >> w[i];
for (int i = 1; i <= n; i ++)
for (int j = m; j >= v[i]; j --)
dp[j] = max(dp[j], dp[j - v[i]] + w[i]);
cout << dp[m];
}
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v[N], w[N];
int dp[N][N];
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++) scanf("%d %d", &v[i], &w[i]);
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++){
dp[i][j] = dp[i - 1][j];
if (j >= v[i]) dp[i][j] = max(dp[i][j], dp[i][j - v[i]] + w[i]);
}
cout << dp[n][m];
}
一维
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v[N], w[N];
int dp[N];
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++) scanf("%d %d", &v[i], &w[i]);
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 << dp[m];
}
状态计算 当不选第 i 种物品,则 f(i,j)=f(i−1,j) 当选第 i 种物品,则 f(i,j)=f(i−1,j−k∗v)+k∗w
f(i,j)=max(f(i−1,j),f(i−1,j−k∗vi)+k∗wi)
二维
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1010;
int v[N], w[N], s[N];
int dp[N][N];
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++) scanf("%d %d %d", &v[i], &w[i], &s[i]);
for (int i = 1; i <= n; i ++)
for (int j = 0; j <= m; j ++)
for (int k = 0; k <= s[i] && k * v[i] <= j; k ++){
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * v[i]] + k * w[i]);
}
cout << dp[n][m] << endl;
}
多重背包可以优化,可以使用滚动数组优化。
一维
#include<iostream>
using namespace std;
const int N = 110;
int f[N];
int main() {
int n, m; cin >> n >> m;
for (int i = 0; i < n; i ++) {
int v, w, s; cin >> v >> w >> s;
for (int j = m; j >= v; j --) {
for (int k = 0; k <= s && k * v <= j; k ++) {
f[j] = max(f[j], f[j - k * v] + k * w);
}
}
}
cout << f[m] << endl;
}
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 15000;
int v[N], w[N];
int f[N];
int main(){
int n, m; cin >> n >> m;
int cnt = 0;
for (int i = 1; i <= n; i ++){
int a, b, s;
cin >> a >> b >> s;
int k = 1;
while (k <= s){
cnt ++;
v[cnt] = a * k;
w[cnt] = b * k;
s -= k;
k <<= 1;
}
if (s > 0) {
cnt ++;
v[cnt] = a * s;
w[cnt] = b * s;
}
}
n = cnt;
for (int i = 1; i <= n; i ++)
for (int j = m; j >= v[i]; j --)
f[j] = max(f[j], f[j - v[i]] + w[i]);
cout << f[m] << endl;
}
#include<iostream>
#include<cstring>
using namespace std;
const int N = 20010;
int f[N], g[N], q[N];
int main() {
int n, m; cin >> n >> m;
for (int i = 0; i < n; i ++) {
int v, w, s; cin >> v >> w >> s;
memcpy(g, f, sizeof f);
for (int j = 0; j < v; j ++) {
int h = 0, t = -1;
for (int k = j; k <= m; k += v) {
if (h <= t && q[h] < k - s * v) h ++;
if (h <= t) f[k] = max(g[k], g[q[h]] + (k - q[h]) / v * w);
while (h <= t && g[k] >= g[q[t]] + (k - q[t]) / v * w) t --;
q[++ t] = k;
}
}
}
cout << f[m];
}
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
int v[N][N], w[N][N];
int s[N];
int f[N];
int main(){
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++ ){
int k; cin >> k;
s[i] = k;
for (int j = 1; j <= k; j ++ ){
cin >> v[i][j] >> w[i][j];
}
}
for (int i = 1; i <= n; i ++)
for (int j = m; j >= 0; j --)
for (int k = 1; k <= s[i]; k ++)
if (j >= v[i][k])
f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);
cout << f[m] << endl;
}
#include<iostream>
using namespace std;
const int N = 12000;
int f[N];
int a[N], b[N], c[N];
int main() {
int n, m; cin >> n >> m;
int t = 1;
for (int i = 0; i < n; i ++) {
int v, w, s; cin >> v >> w >> s;
if (!s) {
a[t] = v;
b[t] = w;
c[t ++] = 1;
} else {
if (s == -1) {
s = 1;
}
int num = 1;
while (num <= s) {
a[t] = num * v;
b[t ++] = num * w;
s -= num;
num *= 2;
}
if (s > 0) {
a[t] = s * v;
b[t ++] = s * w;
}
}
}
n = t;
for (int i = 1; i < n; i ++) {
if (!c[i]) {
for (int j = m; j >= a[i]; j --) {
f[j] = max(f[j], f[j - a[i]] + b[i]);
}
} else {
for (int j = a[i]; j <= m; j ++) {
f[j] = max(f[j], f[j - a[i]] + b[i]);
}
}
}
cout << f[m];
}
#include<iostream>
#include<vector>
using namespace std;
const int N = 110;
int f[N][N], v[N], w[N];
int n, m;
vector<vector<int>> p(N);
void dfs(int u) {
for (int i = v[u]; i <= m; i ++) {
f[u][i] = w[u];
}
for (auto x: p[u]) {
dfs(x);
for (int j = m; j >= v[u]; j --) {
for (int k = 0; k <= j - v[u]; k ++) {
f[u][j] = max(f[u][j], f[u][j - k] + f[x][k]);
}
}
}
}
int main() {
cin >> n >> m;
int head = 0;
for (int i = 1; i <= n; i ++) {
cin >> v[i] >> w[i];
int a; cin >> a;
if (a == -1) {
head = i;
} else {
p[a].push_back(i);
}
}
dfs(head);
cout << f[head][m];
}
我们定义数组 f[i],代表在体积为 i 时的最大价值;数组 c[i],代表在体积为 i 时最优方案数。
#include<iostream>
using namespace std;
const int N = 1010, mod = 1e9 + 7;
int f[N], c[N];
int main() {
int n, m; cin >> n >> m;
for (int i = 0; i <= m; i ++) {
c[i] = 1;
}
for (int i = 1; i <= n; i ++) {
int v, w; cin >> v >> w;
for (int j = m; j >= v; j --) {
if (f[j - v] + w > f[j]) {
f[j] = f[j - v] + w;
c[j] = c[j - v];
} else if (f[j - v] + w == f[j]) {
c[j] = (c[j] + c[j - v]) % mod;
}
}
}
cout << c[m] << endl;
}
#include<iostream>
using namespace std;
const int N = 1010;
int f[N][N], v[N], w[N];
int main() {
int n, m; cin >> n >> m;
for (int i = 1; i <= n; i ++) {
cin >> v[i] >> w[i];
}
for (int i = n; i > 0; i --) {
for (int j = 0; j <= m; j ++) {
f[i][j] = f[i + 1][j];
if (j >= v[i]) {
f[i][j] = max(f[i][j], f[i + 1][j - v[i]] + w[i]);
}
}
}
int j = m;
for (int i = 1; i <= n; i ++) {
if (j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]) {
cout << i << ' ';
j -= v[i];
}
}
}