看到这就应该懂了,考虑递归的话要利用之前的经验。那么 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>usingnamespace std;constint N =1010;intv[N],w[N];intdp[N][N];intmain(){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>usingnamespace std;constint N =1010;intv[N],w[N];intdp[N]; //intmain(){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>usingnamespace std;constint N =1010;intv[N],w[N];intdp[N][N];intmain(){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>usingnamespace std;constint N =1010;intv[N],w[N];intdp[N];intmain(){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>usingnamespace std;constint N =1010;intv[N],w[N],s[N];intdp[N][N];intmain(){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>usingnamespace std;constint N =110;intf[N];intmain() {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>usingnamespace std;constint N =15000;intv[N],w[N];intf[N];intmain(){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>usingnamespace std;constint N =20010;intf[N],g[N],q[N];intmain() {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>usingnamespace std;constint N =12000;intf[N];inta[N],b[N],c[N];intmain() {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];}