4030: 背包
题目内容
有 n n n 个物品,每个物品有大小 w i w_i wi 和价值 v i v_i vi,再给定一个整数 k k k 和背包大小 m m m,对每个 1 ≤ i ≤ n − k + 1 1 \le i \le n - k + 1 1≤i≤n−k+1,求出如果只能选择 i i i 到 i + k − 1 i + k - 1 i+k−1 之间的物品且选择的大小之和不超过 m m m,那么物品价值之和最大是多少。
输入格式
第一行三个整数 n , m , k n, m, k n,m,k。
接下来 n n n 行每行两个整数 w i , v i w_i, v_i wi,vi。
输出格式
输出一行
n
−
k
+
1
n - k + 1
n−k+1 个整数,第
i
i
i 个整数表示只能选择第
i
i
i 到第
i
+
k
−
1
i + k - 1
i+k−1 之间的物品的最大价值。
样例 1 输入
7 8 4
4 4
3 3
2 2
3 1
3 1
2 4
3 4
样例 1 输出
7 6 7 9
#include <bits/stdc++.h>
using namespace std;
template <typename T> void read(T &t) {
t=0; char ch=getchar(); int f=1;
while (ch<'0'||ch>'9') { if (ch=='-') f=-1; ch=getchar(); }
do { (t*=10)+=ch-'0'; ch=getchar(); } while ('0'<=ch&&ch<='9'); t*=f;
}
template <typename T> void write(T t) {
if (t<0) { putchar('-'); write(-t); return; }
if (t>9) write(t/10);
putchar('0'+t%10);
}
template <typename T> void writeln(T t) { write(t); puts(""); }
#define MP make_pair
typedef long long ll;
const int maxn=5010;
int n,k,m;
int L[maxn],R[maxn],w[maxn],v[maxn];
ll f[maxn][maxn],g[maxn][maxn];
void chkmax(ll &x,ll y) { if (x<y) x=y; }
int main() {
read(n),read(m),read(k);
for (int i=1;i<=n;i++) read(w[i]),read(v[i]);
for (int l=1,r;l<=n;l=r+1) {
r=min(n,l+k-1);
for (int i=l;i<=r;i++) {
L[i]=l,R[i]=r;
if (i==l) f[i][w[i]]=v[i];
else {
for (int j=0;j<=m;j++) {
chkmax(f[i][j],f[i-1][j]);
if (j>=w[i]) chkmax(f[i][j],f[i-1][j-w[i]]+v[i]);
}
}
for (int j=1;j<=m;j++) chkmax(f[i][j],f[i][j-1]);
}
for (int i=r;i>=l;i--) {
if (i==r) g[i][w[i]]=v[i];
else {
for (int j=0;j<=m;j++) {
chkmax(g[i][j],g[i+1][j]);
if (j>=w[i]) chkmax(g[i][j],g[i+1][j-w[i]]+v[i]);
}
}
for (int j=1;j<=m;j++) chkmax(g[i][j],g[i][j-1]);
}
}
for (int i=1;i<=n-k+1;i++) {
int j=i+k-1; ll res=0;
if (L[i]==L[j]) res=f[j][m];
else {
for (int v=0;v<=m;v++) chkmax(res,g[i][v]+f[j][m-v]);
}
printf("%lld ",res);
} puts("");
return 0;
}