F - Schrödinger's Knapsack ZOJ - 4019

题意:有两种物品价值分别为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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值