ZOJ 4019 Schrödinger‘s Knapsack dp

传送门:https://zoj.pintia.cn/problem-sets/91827364500/problems/91827370240

题意

给一个背包,体积为c,有两类物品,第一类有n个,权值为k1,第二类有m个,权值为k2。每个物品都有自己的体积。

当把一个物品放进去之后,总贡献增加$k*$放入之后剩余体积。

问,最大贡献多少?

思路

体积越小,先让进去最后,所以要先排序,从小到大。

设f[i][j]表示放入第一类i个,第二类j个。则下一个是放什么呢? 可能是第一类下一个,也可能是第二类下一个。 $$f[i][j]=max(f[i-1][j]+k1*v,f[i][j-1]+k2*v)$$

这里的v是剩余体积,也就是V-已经放入体积。

然后注意边界的选取即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
##include "bits/stdc++.h"
using namespace std;

typedef long long ll;

void solve() {
int _; cin >> _;
while(_--) {
ll k1, k2, V; cin >> k1 >> k2 >> V;
int n, m; cin >> n >> m;
vector<vector<ll>> f(n + 1, vector<ll>(m + 1));
vector<ll> a(n + 1), b(m + 1);
for(int i = 1;i <= n; i++) cin >> a[i];
for(int i = 1;i <= m; i++) cin >> b[i];
sort(a.begin() + 1, a.begin() + n + 1);
sort(b.begin() + 1, b.begin() + m + 1);
for(int i = 1;i <= n; i++) a[i] += a[i - 1];
for(int i = 1;i <= m; i++) b[i] += b[i - 1];
ll ans = 0;
for(int i = 0;i <= n; i++) {
for(int j = 0;j <= m; j++) {
if (i == 0 && j == 0) continue;
if (i == 0) {
if (V >= b[j]) f[i][j] = f[i][j - 1] + k2 * (V - b[j]);
}
else if (j == 0) {
if (V >= a[i]) f[i][j] = f[i - 1][j] + k1 * (V - a[i]);
}
else {
f[i][j] = max(f[i - 1][j] + k1 * (V - a[i] - b[j]), f[i][j - 1] + k2 * (V - a[i] - b[j]));
}
ans = max(ans, f[i][j]);
}
}
cout << ans << endl;
}
}

signed main() {
solve();
}

本文作者:jujimeizuo
本文地址https://blog.jujimeizuo.cn/2021/04/08/zoj-4019-schrodingers-knapsack/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!