CodeForces - 366C Dima and Salad 01背包变形 好题!

题目连接:https://vjudge.net/contest/153156#problem/D

题意:

给出n个物品,有两个属性,问最后第一个属性的总和是第二个属性的k倍的时候,第一个属性最大是多少。

思路:

本来背包做的就不多,这个题让我深度认识了背包

对于这个题由于暴力的情况太多,所以就开始往dp靠拢....我们发现每个物品只有一件,又让求最大值... 很像01背包啊

这个题给了我们条件 要求相除为k,可是都是int,做除法不行,只能想办法转移一下等式 得到a[i]-k*b[i]=0;

那么我们就可以把a[i]看成价值,并把每件物品的a[i]-k*b[i]看成重量,由于这个过程中a[i]-k*b[i]会有负的,所以我们就可以开两个数

组,然后去对正的背一次包,对负的背一次包,我们最后要求的就是背包的容量为0即可, 即枚举两个背包中重量相等的.

注意:

我们需要明白的是,我们那种普通背包,背包不一定要装满, 也就是说背包容量里所有的状态都是可能的,但是我们这个题是必须要

凑出那么多的重量的,否则一些不存在的状态会影响最后的结果.所以我们对dp数组初始化的时候就不能初始化为0,要排除那些不存在的

状态,只去更新那些可能的状态!

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+10;
int dp1[111*111];
int dp2[111*111];
int a[111],b[111];
int n,k;
struct node
{
	int w;
	int v;
}q[111];
int main()
{
	memset(dp1,-1,sizeof(dp1));
	memset(dp2,-1,sizeof(dp2));
	cin>>n>>k;
	dp1[0]=0;
	dp2[0]=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=n;i++)
	{
	   cin >>b[i];
	   q[i].w=a[i]-k*b[i];
	   q[i].v=a[i];
	}
	for(int i=1;i<=n;i++)
	{
		if(q[i].w<0)
		{
			q[i].w=-q[i].w;
		for(int j=maxn;j>=q[i].w;j--)
		{
			if(dp1[j-q[i].w]!=-1)
			dp1[j]=max(dp1[j],dp1[j-q[i].w]+q[i].v);	
		}
		}
		else
		{	
		for(int j=maxn;j>=q[i].w;j--)
		{	if(dp2[j-q[i].w]!=-1)//只要那些可能的状态
			dp2[j]=max(dp2[j],dp2[j-q[i].w]+q[i].v);	
		}	
		}
	}
	int ans=0;
	for(int i=0;i<maxn;i++)
	{
		  if(dp1[i]!=-1&&dp2[i]!=-1)
		  //cout<<i<<" "<<dp1[i]+dp2[i]<<endl;
		  ans=max(dp1[i]+dp2[i],ans);
		  //cout<<i<<endl;
	}
	if(ans!=0)
	printf("%d\n",ans);
	else
	printf("-1\n");
	return 0;
	
} 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marcus-Bao

万水千山总是情,只给五角行不行

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值