题目描述
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 1≤n≤2000)。接下来 n n n 行每行每件商品由一对数 t i t_i ti, c i c_i ci( 0 ≤ t i ≤ 2000 0 \le t_i \le 2000 0≤ti≤2000, 1 ≤ c i ≤ 1 0 9 1 \le c_i \le 10^9 1≤ci≤109)描述。如果 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记录
本人是个蒟蒻,学艺不精,如果有什么问题或建议,请在评论区指出