思路
首先考虑贪心,按 \(f\) 进行从小到大排序。特别的,当 \(f\) 相等时,就按价格进行排序。
然后我们就可以用类似 01 背包的方法,为了方便,我们可以将计算机的价格置为负数。定义状态 \(dp_j\) 表示内核数为 \(j\) 时所得的最大利润。背包容量即为所购买的计算机内核的总和 \(tot\)。
所以状态转移方程即为
\[dp_{j+c_i}\gets \max dp_{j+c_i}, dp_j+v_i \]这里要注意的是,当处理的是计算机时需要倒叙枚举,反正则倒叙
时间复杂度 \(O((n+m)\displaystyle\sum_{i=1}^n p_i)\)
Code.
#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m;
struct node {
int c, f, v;
} a[4005];
bool cmp(node x, node y) {
return x.f == y.f ? x.v < y.v : x.f > y.f;
}
int dp[200005], tot;
signed main() {
scanf("%lld", &n);
for (int i = 1; i <= n; i++) {
scanf("%lld %lld %lld", &a[i].c, &a[i].f, &a[i].v);
a[i].v *= -1;
}
scanf("%lld", &m);
for (int i = n + 1; i <= m + n; i++) {
scanf("%lld %lld %lld", &a[i].c, &a[i].f, &a[i].v);
}
sort(a + 1, a + n + m + 1, cmp);
memset(dp, 128, sizeof(dp));
dp[0] = 0;
for (int i = 1; i <= n + m; i++) {
if (a[i].v < 0) {
for (int j = tot; j >= 0; j--) dp[j + a[i].c] = max(dp[j + a[i].c], dp[j] + a[i].v);
tot += a[i].c;
} else {
for (int j = 0; j <= tot; ++j) dp[j] = max(dp[j], dp[j + a[i].c] + a[i].v);
}
}
int ans = 0;
for (int i = 0; i <= tot; i++) {
ans = max(ans, dp[i]);
}
printf("%lld", ans);
return 0;
}