【洛谷CF19B(codeforces19B)】Checkout Assistant

作者:乐天JOE
洛谷题目传送门
CF原题面传送门



题目描述

Bob 来到一家现购自运商店,将 n n n 件商品放入了他的手推车,然后到收银台付款。每件商品由它的价格 c i c_i ci 和收银员扫描它的时间 t i t_i ti 秒定义。

当收银员正在扫描某件商品时,Bob 可以从他的手推车中偷走某些其它商品。Bob 需要恰好 1 1 1 秒来偷走一件商品。Bob 需要付给收银员的最少钱数是多少?请记住,收银员扫描商品的顺序由 Bob 决定。


输入格式

输入第一行包含数 n n n 1 ≤ n ≤ 2000 1 \le n \le 2000 1n2000)。接下来 n n n 行每行每件商品由一对数 t i t_i ti c i c_i ci 0 ≤ t i ≤ 2000 0 \le t_i \le 2000 0ti2000 1 ≤ c i ≤ 1 0 9 1 \le c_i \le 10^9 1ci109)描述。如果 t i t_i ti 0 0 0,那么当收银员扫描商品 i i i 时,Bob 不能偷任何东西。


输出格式

输出一个数字—— Bob 需要支付的最小金额是多少。


样例 #1

样例输入 #1

4
2 10
0 20
1 5
1 3

样例输出 #1

8

样例 #2

样例输入 #2

3
0 1
0 10
0 100

样例输出 #2

111

思路

题目的方向不是很准确告诉你用什么算法。

所以我就踩坑了。描写一下我的心路历程。


思路一:贪心

乍一看题目要输出的答案:Bob 需要支付的最小金额是多少。我想到了贪心,想了想,决定了贪心策略。

是这样子的:把需要最多时间的拿去给收银员扫描,让其他的物品有时间偷

于是代码就出来了:

#include<bits/stdc++.h>
#define int long long
#define itn int
typedef unsigned long long ull;
using namespace std;
int n,i,j,ans;
struct node
{
	int t,c;
}a[2005];
bool cmp(node x,node y)
{
	return x.t>y.t;
}
signed main()
{
	cin>>n;
	j=n+1;
	for(int i=1;i<=n;i++)
		cin>>a[i].t>>a[i].c;
	sort(a+1,a+n+1,cmp);
	while(i<j)
	{
		ans+=a[i].c;
		i++;
		for(int k=1;k<=a[i].t;i++)
			j--;
	}
	cout<<ans;
	cout<<"\n";
	return 0;
}

不过很显然,连样例都过不了,这是为什么呢,我们看一下贪心策略有没有什么漏洞。

仔细观察,发现在我们的策略中如果需要扫描很久的物品很值钱的话,还是选不了,所以贪心显然是错的


思路二:背包

第二个思路便是背包了,我来讲一下我是如何想到他的。

首先,为什么他让我们求的是需要支付的最小金额而不是最大剩余金额呢?先别想着喷我,往下看。

正是因为这是背包,想一下要求的金额来自哪里,来自 c i c_i ci说明了 c i c_i ci就是背包问题中物品的价值

然后物品重量就是时间,也就是 t i + 1 t_i+1 ti+1(加一是因为还有 收银员正在扫的哪一个)

背包容量则是 max ⁡ ( t ) + n \max(t)+n max(t)+n

记得是最小值,要初始化。而且答案是 d p n dp_n dpn之后的最小值


思路二坑点

  • 初始化用memset,不要用for
  • dp数组记得开 2 n 2n 2n,也就是4000
  • dp数组不要赋太大的值
  • 不要忘记 d p 0 = 0 dp_0=0 dp0=0
  • 不开long long见祖宗!!!

AC code

看代码

#include<bits/stdc++.h>
#define int long long
#define itn int
typedef unsigned long long ull;
using namespace std;
int n,m,t[2005],c[2005],dp[4005],ans=2e12; //ans开这么大的原因是全部买有可能怎么大 
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>t[i]>>c[i];
		t[i]++; //别忘了重量是t[i]+1 
		m=max(m,t[i]);  
	}
	m+=n;
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0; //这个初始化不能忘
	for(int i=1;i<=n;i++) //01背包模板 
		for(int j=m;j>=t[i];j--)
			dp[j]=min(dp[j],dp[j-t[i]]+c[i]);
	for(int i=n;i<=m;i++) //从n开始是因为要买完所有商品 
		ans=min(ans,dp[i]);
	cout<<ans;
	cout<<"\n";
	return 0;
}

AC记录
本人是个蒟蒻,学艺不精,如果有什么问题或建议,请在评论区指出

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值