滚动数组
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> const int INF = 1e9; int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int t; while (scanf("%d", &t) != EOF) { int caseid = 0; while (t--) { int n; scanf("%d", &n); int w[101] = {0}; int cnt = 0; bool hasZero = false; for (int i = 1; i <= n; ++i) { scanf("%d", &w[++cnt]); if (w[cnt] == 0) { cnt--; hasZero = true; } } n = cnt; int dp[2][4001]; int offset = 2000; for (int i = 0; i < 4001; ++i) dp[0][i] = -INF; dp[0][offset] = 0; int *des = dp[0]; int *src = dp[1]; for (int i = 1; i <= n; ++i) { std::swap(des, src); for (int j = -2000; j <= 2000; ++j) { int temp = -INF; if (j + w[i] <= 2000 && src[j + offset + w[i]] != -INF) temp = src[j + offset + w[i]] + w[i]; if (j - w[i] >= -2000 && src[j + offset - w[i]] != -INF) temp = std::max(temp, src[j + offset - w[i]] + w[i]); des[j + offset] = std::max(temp, src[j + offset]); } } printf("Case %d: ", ++caseid); if (des[offset] == 0) puts(hasZero ? "0" : "-1"); else printf("%d ", des[offset] / 2); } } return 0; }
二维背包问题是指每件物品都具有两种不同的开销,选择这件物品必须同时承担这两种开销,在选择物品的时候必须保证两种开销都不会超过相应的背包容量,求选择物品可以得到最大的权重。设第i件物品所需的两种开销分别为v[i]和u[i],两种开销所对应的背包容量分别为V和U,物品的价值为w[i]。
分析:相比经典的01背包问题,二维背包问题增加了一维开销,于是我们需要在状态上增加一维。设s[i][j][k]表示将前i件物品放入两种容量分别为j和k的背包时所能获得的最大权重,则状态转移方程为s[i][j][k]=max{s[i-1][j][k], s[i-1][j-v[i]][k-u[i]]+w[i]},递推边界为当i=0时s[i][j][k]=0。和01背包类似,状态的维数可以很容易地从三维降低到二维,具体实现见代码。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <cstdio> #include <algorithm> int main() { #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif int t; while (scanf("%d", &t) != EOF) { while (t--) { int n, m, l; int val[101]; int lon[101]; int dp[101][1001] = {0}; scanf("%d%d%d", &n, &m, &l); for (int i = 1; i <= n; ++i) scanf("%d%d",&lon[i], &val[i]); for (int i = 1; i <= m; ++i) { for (int j = 0; j <= l; ++j) dp[i][j] = -1e9; } for (int i = 1; i <= n; ++i) { for (int j = l; j >= lon[i]; --j) for (int k = m; k >= 1; --k) dp[k][j] = std::max(dp[k][j], dp[k - 1][j - lon[i]] + val[i]); } if (dp[m][l] > 0) printf("%d ", dp[m][l]); else puts("0"); } } return 0; }