CF730J.Bottles(有限制条件的0/1背包)

题目链接:https://vjudge.net/contest/373875#problem/J
题意:给n个瓶子,每个瓶子放了一些水,现在要把这些水尽可能汇总到最少的瓶子了,问最少的瓶子数与移到这些瓶子里所要的最小代价
解题思路:
最少瓶子数很好求,直接先把水的总量rsum求出来,然后从大的容量的瓶子开始放,就能得到最少瓶子数k
求最小的代价,就相当于从总的瓶子里面找出k个能放入rsum水的瓶子,并且这些瓶子中本来的水的量最多
利用0/1背包,dp[i][j]表示容量为i、选取了j个物品的最大价值
将n个瓶子看成n个物品,每个物品价值为瓶子中的水bot[i].r,占用空间为bot[i].v,求取k个瓶子占用空间大于等于rsum的最大价值。
0/1背包部分我花了好长时间才写出来,一直在想该怎么处理选择k个物品,哭了
DP主体:

void DP(int index,int vsum)
{
	for(int i=0;i<=vsum;i++)
			for(int j=0;j<=k;j++)
				dp[i][j]=-99999999;
	dp[0][0]=0;
	for(int i=1;i<=index;i++){
			for(int j=vsum;j>=bot[i].v;j--){
				for(int p=k;p>=1;p--){
					dp[j][p]=max(dp[j][p],dp[j-bot[i].v][p-1]+bot[i].r);
				}
			}
		}
}
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n;
int rsum;
int vsum;
int k;
int dp[11000][110];
struct node{
	int v;
	int r;
}bot[110];
bool cmp(node a,node b)
{
	return (a.v==b.v)?(a.r>b.r):(a.v>b.v);
}
void DP(int index,int vsum)
{
	for(int i=0;i<=vsum;i++)
			for(int j=0;j<=k;j++)
				dp[i][j]=-99999999;
	dp[0][0]=0;
	for(int i=1;i<=index;i++){
			for(int j=vsum;j>=bot[i].v;j--){
				for(int p=k;p>=1;p--){
					dp[j][p]=max(dp[j][p],dp[j-bot[i].v][p-1]+bot[i].r);
				}
			}
		}
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)  scanf("%d",&bot[i].r),rsum+=bot[i].r;
	for(int i=1;i<=n;i++)  scanf("%d",&bot[i].v),vsum+=bot[i].v;
	sort(bot+1,bot+1+n,cmp);
	int tmp=rsum;
	int res=-999999;
	int index=0;
	for(int i=1;i<=n;i++){
		if(tmp>0)
			k++,tmp-=bot[i].v;
		else{
			res=tmp+bot[i-1].v;
			break;
		}
	}
	int t=rsum;
	index=k;
		for(int i=k;i<=n;i++)
		    if(res<=bot[i].v){
				index=i;
			}
			else
				break;
		DP(index,vsum);
		int maxs=0;
		for(int i=rsum;i<=vsum;i++)
			maxs=max(maxs,dp[i][k]);
		t-=maxs;
		printf("%d %d\n",k,t);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Buyi.

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值