#include <bits/stdc++.h>
using namespace std;
const int maxn = 205, maxm = 1e6 + 5;
int a[maxn], b[maxn], sz[maxm], siz[maxn];
int f[maxn][maxn][maxn];//f[i][j][k]表示用k的容量在[i, j]中选物品的最大价值
int g[maxn][maxn];//g[i][j]表示用前i个背包,在前j件物品选,能获得的最大价值
int main()
{
int n, m, i, j, k;
cin >> n >> m;
for (i = 1; i <= n; i++)
{
cin >> a[i] >> b[i];
}
for (i = 1; i <= m; i++)
{
cin >> sz[i];
}
int cnt = 0;//因为每次至少要取一件物品,所以只贪心地用后n个背包
for (i = max(1, m - n + 1); i <= m; i++)
{
siz[++cnt] = sz[i];
}
for (i = 1; i <= n; i++)
{
for (j = i; j <= n; j++)
{
for (k = 0; k <= 200; k++)
{
f[i][j][k] = f[i][j - 1][k];
if (k >= a[j])
f[i][j][k] = max(f[i][j][k], f[i][j - 1][k - a[j]] + b[j]);
//每个背包不一定是从前i件物品选,所以维护区间范围选物品的背包
}
}
}
for (i = 1; i <= cnt; i++)
{
for (j = 1; j <= n; j++)
{
for (k = 0; k <= j; k++)
{
g[i][j] = max(g[i][j], g[i - 1][k] + f[k + 1][j][siz[i]]);//前i个背包选到j,那么前i-1个可能选到0~j
}
}
}
cout << g[cnt][n];
return 0;
}
区间选物品的多个01背包
于 2023-11-16 00:03:05 首次发布