ZOJ 4019 (动态规划)

本文详细解析了一道关于背包问题的动态规划题目,通过实例介绍了如何处理与剩余容量相关的价值计算,强调了物品排序和动态规划方程的重要性,并提供了完整的代码实现。

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

题目链接:https://vjudge.net/problem/ZOJ-4019

题意 

有个容量为c的背包,两类物品,其权值分别为k1、k2,第一种物品有n个,第二种有m个,每个物体都有自己的体积。当放进一个物体进入背包时,其获得的价值的对应的权值k乘上放入当前物体后剩余的容量。现在问,能够获得的最大价值是多少?

思路:

因为价值与物体放入后剩余的容量有关,所以,对于同一类物品,先放入体积较小的物品,所以对于同一类的物品,按照体积从小到大排一下序。接下来,重要的是找到正确的动态规划方程。

用dp[i][j]表示,将i个第一种物品,j个第二种物品,放入背包中,所能获得的最大价值。

动态规划方程:dp[i][j]=dp[i-1][j]+V余*k1  ||  dp[i][j]=dp[i][j-1]+V余*k2; (V余>=0)

注意体积,可以用V[i][j]表示i个第一种物品,j个第二种物品放入后所占用的体积。

 

附上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
using namespace std;
ll t,c,n,m,k1,k2;
ll a[2005],b[2005];
ll dp[2005][2005],sum[2005][2005];
int main()
{
	cin>>t;
	while(t--)
	{
	    scanf("%lld%lld%lld",&k1,&k2,&c);
		scanf("%lld%lld",&n,&m);
		ll i,j,k;
		for(i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
		}
		for(i=1;i<=m;i++)
		    scanf("%lld",&b[i]);
		sort(a+1,a+n+1);sort(b+1,b+m+1);
		j=max(n,m);
		for(i=0;i<=j;i++)
		{
			for(k=0;k<=j;k++)dp[i][k]=0,sum[i][k]=0;//初始化 
		}
		ll ans=0;
		for(i=0;i<=n;i++){
			for(j=0;j<=m;j++)
			{
				if(i>0&&(c-a[i]-sum[i-1][j])>=0)//动态规划方程的条件 
				{
					if((dp[i-1][j]+k1*(c-a[i]-sum[i-1][j]))>dp[i][j]){
						dp[i][j]=dp[i-1][j]+k1*(c-a[i]-sum[i-1][j]);
						sum[i][j]=sum[i-1][j]+a[i];
					}
				}
				if(j>0&&(c-b[j]-sum[i][j-1])>=0)//动态规划方程的条件 
				{
					if(dp[i][j]<(dp[i][j-1]+k2*(c-b[j]-sum[i][j-1]))){
						dp[i][j]=dp[i][j-1]+k2*(c-b[j]-sum[i][j-1]);
						sum[i][j]=sum[i][j-1]+b[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、付费专栏及课程。

余额充值