题意:有两种物品价值分别为k1, k2, 数量分别有n, m个,接下来输入他们所占的空间大小,问怎么放才能使得空间为c的背包里价值最大
解法:才开始读题发现类似于01背包,但是无奈数据量太大,后来证明也是不对的,但是这个题肯定是dp没跑了,但那是转移方程没有找到。
分析:两种物品的价值分别都是一样的,所以要优先放体积最小的才能让结果最优,出于这个目的,建立dp[i][j], 表示取第一个物品的前i个,第二个物品的前j个,到此怎么转移成了主要的问题,dp[i][j] ,可以有dp[i - 1][j] 和 dp[i][j - 1] 转移而来,所以dp[i][j] = max(dp[i - 1][j] + b1[i].v * (c - sum), dp[i][j - 1] + b2[j].v * (c - sum)); 这里的sum指放入第i个a物品或者第j个b物品所使用的空间。
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define met(a, b) memset(a, b, sizeof(a))
typedef long long ll;
const int maxn = 2e3 + 50;
struct BAG {
ll w, v;
} b1[maxn], b2[maxn];
ll cmp(BAG a, BAG b) {
return a.w < b.w;
}
ll dp[maxn][maxn];
ll suma[maxn], sumb[maxn];
int main() {
#define int long long
int T, n, m, k1, k2, c;
scanf("%lld", &T);
while(T--) {
int d;
suma[0] = sumb[0] = 0;
scanf("%lld%lld%lld", &k1, &k2, &c);
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%lld", &d);
b1[i].w = d;
b1[i].v = k1;
}
for(int i = 1; i <= m; i++) {
scanf("%lld", &d);
b2[i].w = d;
b2[i].v = k2;
}
sort(b1 + 1, b1 + n + 1, cmp);
sort(b2 + 1, b2 + m + 1, cmp);
for(int i = 1; i <= n; i++) {
suma[i] = suma[i - 1] + b1[i].w;
}
for(int i = 1; i <= m; i++) {
sumb[i] = sumb[i - 1] + b2[i].w;
}
int ans = 0;
for(int i = 0; i <= n; i++) {
for(int j = 0; j <= m; j++) {
dp[i][j] = 0;
if(i == 0 && j == 0) continue;
if(i == 0) {
if(c >= sumb[j]);
dp[i][j] = dp[i][j - 1] + k2 * (c - sumb[j]);
} else if(j == 0) {
if(c >= suma[i]);
dp[i][j] = dp[i - 1][j] + k1 * (c - suma[i]);
} else {
int sum = suma[i] + sumb[j];
if(c - sum < 0) continue;
dp[i][j] = max(dp[i - 1][j] + k1 * (c - sum), dp[i][j - 1] + k2 * (c - sum));
}
ans = max(ans, dp[i][j]);
}
}
printf("%lld\n", ans);
}
return 0;
}