ZOJ 4019 Schrödinger's Knapsack

本文介绍了一种针对两类物品的优化选择算法,通过动态规划方法实现最优价值组合的选择。适用于物品价值固定、背包容量较大的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意: 有两大类物品, 第一类物品的价值均为K1, 第二类物品的价值均为K2。    

           背包容量为c。

           每组数据的第三行代表第一类物品的体积,第四行代表第二类物品体积。

           对于背包的贡献计算方式为           ( 当前容量 - 选取物品的体积) * 物品种类的价值。

           由于容量C太大,所以肯定是不能背包来做。

           所以可以考虑dp[i][j] ( i 代表第一类物品选了i个 ,  j 代表第二类物品选了j个)。

think: 首先简化这个问题, 只选一种物品, 那肯定优先选体积小的,因为价值相同。

          所以可以先排下序,预处理出 两种物品的前缀和 与 dp[i][0]    与   dp[0][j]

          然后根据容量转移一下。

#include <bits/stdc++.h>
#define ll long long
#define ms(x) memset(x, 0, sizeof(x))
using namespace std;
const int N = 2003;
ll dp[N][N];
ll suma[N], sumb[N];
ll a[N], b[N];
int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        ll k1, k2, c;
        int n, m;
        scanf("%lld%lld%lld",&k1, &k2, &c);
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%lld", &a[i]);
        }
        for(int i=1;i<=m;i++){
            scanf("%lld", &b[i]);
        }
        sort(a+1, a+n+1);sort(b+1, b+m+1);
        suma[0] = 0; sumb[0] = 0;
         for(int i=1;i<=n;i++){
            suma[i] = a[i] + suma[i-1];
        }
        for(int i=1;i<=m;i++){
            sumb[i] = b[i] + sumb[i-1];
        }
        for(int i=0;i<=n;i++)
            for(int j=0;j<=m;j++)
                dp[i][j] = 0;
        ll ans = 0;
        for(int i=1;i<=n;i++){
            if(c>=suma[i])
                dp[i][0] = dp[i-1][0]+(c - suma[i])*k1;
            ans = max(ans, dp[i][0]);
        }
        for(int i=1;i<=m;i++){
            if(c>=sumb[i])
                dp[0][i] = dp[0][i-1]+(c - sumb[i])*k2;
            ans = max(ans, dp[0][i]);
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(c >= sumb[j]+suma[i]){
                    dp[i][j] = max(dp[i][j], dp[i][j-1] + k2*(c - sumb[j] - suma[i])),
                    dp[i][j] = max(dp[i][j], dp[i-1][j] + k1*(c - suma[i] - sumb[j]));
                }
                else if(c>= suma[i] + sumb[j-1]){
                    dp[i][j] = max(dp[i][j], dp[i][j-1]);
                }
                else if(c>= suma[i-1] + sumb[j]){
                    dp[i][j] = max(dp[i][j], dp[i-1][j]);
                }
                ans = max(ans, dp[i][j]);
            }
        }
        printf("%lld\n", ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值