一二计划(Day 6)牛牛去买球

题目:https://ac.nowcoder.com/acm/problem/21668

题目描述:

一个人如果在他很小的时候就自己赚过钱,他的一生都会过得非常节俭,因为他知道财富来之不易.

作为一个勤俭节约的好孩子,牛牛决定在生活中践行这一原则.

有一天他想去商店买一些球来玩,他发现商店里有n个盒子,每个盒子外面有一张标签告诉你有ai个红球,bi个蓝球,需要ci的钱购买

但是由于店主是一个粗心的人,他告诉你每个盒子球的总量是符合标签的说明的,但是具体的种类可能会有如下偏差,比如可能有

(ai+1 ,bi-1),(ai, bi), (ai-1, bi+1)三种可能

牛牛 想要买至少K个同颜色的球,但是他又不想浪费钱.

帮他算算最少花多少钱买盒子能够使得至少会有K个球是同色的

解题思路

典型的背包01问题
需要注意的是有可能有(-1~1)的偏差,所以我们在dp时都考虑最差的情况,考虑都只有ai-1和bi-1个球

因此我们设dp[j]为买j个球最少需要花的钱

1.dp关系为 dp[j]=min(dp[j],dp[j-(a[i]-1)+c[i]])//j>=a[i]-1,a[i]为当前这个箱子i个球,dp[j]为当前总数j个球 ,当前总数球价值=当前箱子i个球的价值+之前dp算的j-i个球的价值,因为时考虑最差情况所以时是-(i-1)

2.注意还有一种情况(看了别人的答案才明白的),就是不管你抓什么球,只要抓的球总数>=2k-1 就一定会有一种球的颜色的个数>=k(因为平均情况为k 和k-1,所以肯定会有>=k)

此时dp关系为 dp[j]=min(dp[j],dp[j]-(a[i]+b[i])+c[i])

因为C语言里没有取最小值的函数 ,不好用地址来写,所以直接用别人的C++代码,思路是一样的


#include<bits/stdc++.h>
using namespace std;
const int maxn=2e4+100;
const int inf=0x3f3f3f3f;
int a[55],b[55],c[55],dp[maxn];
int main()
{
	int n,k,ans,v=2e4-2;
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int i=1;i<=n;i++) scanf("%d",&b[i]);
	for(int i=1;i<=n;i++) scanf("%d",&c[i]);
	memset(dp,inf,sizeof(dp));
	dp[0]=0;ans=inf;
	for(int i=1;i<=n;i++)
		for(int j=v;j>=(a[i]-1);j--)
			dp[j]=min(dp[j],dp[j-(a[i]-1)]+c[i]);
	for(int i=k;i<=v;i++) ans=min(ans,dp[i]);
	memset(dp,inf,sizeof(dp));
	dp[0]=0;
	for(int i=1;i<=n;i++)
		for(int j=v;j>=(b[i]-1);j--)
			dp[j]=min(dp[j],dp[j-(b[i]-1)]+c[i]);
	for(int i=k;i<=v;i++) ans=min(ans,dp[i]);
	memset(dp,inf,sizeof(dp));
	dp[0]=0;
	for(int i=1;i<=n;i++)
		for(int j=v;j>=(a[i]+b[i]);j--)
			dp[j]=min(dp[j],dp[j-(a[i]+b[i])]+c[i]);
	for(int i=2*k-1;i<=v;i++) ans=min(ans,dp[i]);
	if(ans==inf) puts("-1");
	else printf("%d\n",ans);
	return 0;
}

10000小时计划
90h
淦 放纵了自己一晚上 晚上十一点才开始为了完成任务而去刷一道题哎

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值