[背包]CF19B Checkout Assistant 题解

背包好题,也包含了一种思想。

题意

有若干物品,每个物品有两个属性 ai , bi ,表示这个物品的费用 ai 以及如果选择了这个物品我可以白嫖 bi 个物品。最小的费用数。

主要思想

如果我们正向考虑,似乎十分难想到一个贪心策略。就算我现在知道了我们现在有选择 j 个物品的机会,我们也不知道选择给谁这个机会,所以说我们似乎不能从正面开始考虑。

正确的思路是将选择 j 个物品的机会想成是一个容量为 j+1 的物品,为什么?因为我们可以想到,如果我们有选择 j 个物品的机会,我们可以记在那里,不去想选哪 j 个物品最好,而是看看我选完这 j 个物品之后选什么。那么如果我把它想成一个 j+1 的物品,我只要到容量大于等于 n 就行了。

这样的话我们的话就可以转成一个 01 背包的问题了。记得要开 long long 。

并且学到了一个新的东西, memset 对于 long long 的数组初始化也会初始化到 long long 可以承受的最大值的。

代码

#include <bits/stdc++.h>
#define debug puts("I love Newhanser forever!!!!!");
#define pb push_back
using namespace std;
template <typename T>inline void read(T& t){
    t=0; register char ch=getchar(); register int fflag=1;
    while(!('0'<=ch&&ch<='9')){if(ch=='-') fflag=-1;ch=getchar();}
    while(('0'<=ch&&ch<='9')){t=t*10+ch-'0'; ch=getchar();} t*=fflag;
}
const int MAXN=5086;
typedef long long ll;
int n,V,v[MAXN];
ll dp[MAXN],c[MAXN];
int main(){
	read(n);
	for(int i=1;i<=n;++i){
		read(v[i]);
		v[i]++;
		read(c[i]);
		V=max(v[i],V); 
	}
	V+=n;
	memset(dp,0x3f,sizeof(dp));
	dp[0]=0;
	for(int i=1;i<=n;++i)
		for(int j=V;j>=v[i];--j)
			dp[j]=min(dp[j-v[i]]+c[i],dp[j]);
	ll ans=2e12;
	for(int j=n;j<=V;++j) ans=min(ans,dp[j]);
	cout<<ans<<endl;
    return 0;
}
posted @   Mercury_City  阅读(44)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示