ZOJ 4019F - Schrödinger's Knapsack --补题 dp

题目:给两个序列,两个序列的系数分别为k1,k2,有一个背包容量为c,从两个序列里面取数(这个数相当于放入物品的体积)放入到背包中,使得背包里面装的价值最大

条件:1,每次放进背包里面的价值=背包剩余的体积*放入物品对应序列的系数

输入:输入t组数据

          k1,k2,c(1<=k1,k2,c<=10的7次方)

          输入两个序列的长度n,m(1<=n,m<=2000)

          输入两个序列中每个物品的体积(1<=每个体积<=10的7次方)

输出:背包的最大价值

思路:是一道dp问题,每次选择的时候肯定是剩余的体积越大越好,那么选取的物品肯定是体积越小越好,不能一直对比取每次最小的体积,因为剩余的体积会变。先对每个序列的体积进行排序,每个序列的排序后的前缀和是一定要算的。状态转移方程:dp[i][j]=max(dp[i][j-1]+k2*(cn-suma[i]-sumb[j]),dp[i-1][j]+k1*(cn-suma[i]-sumb[j]))。

代码:

#include <iostream>
#include <map>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=2005;
int a[maxn+1],b[maxn+1];
long long int suma[maxn+1],sumb[maxn+1];//前缀和
long long int dp[maxn+1][maxn+1];//dp
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int k1,k2,cn;
        scanf("%d%d%d",&k1,&k2,&cn);
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        for(int i=1;i<=m;i++)
        scanf("%d",&b[i]);
        sort(a+1,a+n+1);
        sort(b+1,b+m+1);
        sumb[0]=0;
        suma[0]=0;
        long long int ans=0;
        for(int i=1;i<=n;i++)//计算前缀和
        {
            suma[i]=suma[i-1]+a[i];
        }
        for(int i=1;i<=m;i++)
        {
            sumb[i]=sumb[i-1]+b[i];
        }
        dp[0][0]=0;
        for(int i=1;i<=m;i++)//先把没有选其它序列的前缀和时的dp写出来
        {
            dp[0][i]=dp[0][i-1]+(cn-sumb[i])*k2;
            ans=max(ans,dp[0][i]);
        }
        for(int i=1;i<=n;i++)
        {
            dp[i][0]=dp[i-1][0]+(cn-suma[i])*k1;
            ans=max(ans,dp[i][0]);
        }
        for(int i=1;i<=n;i++)//开始dp
        {
            for(int j=1;j<=m;j++)
            {
                if(suma[i]+sumb[j]<=cn)
                {
                    dp[i][j]=max(dp[i][j-1]+k2*(cn-suma[i]-sumb[j]),dp[i-1][j]+k1*(cn-suma[i]-sumb[j]));
                    ans=max(ans,dp[i][j]);
                }
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

总结:1,回顾了一下dp    2,排位赛的时候没有看这题有点亏,读英文题的不够耐心,每次比赛都没有把所有的题目都看过一遍

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值