牛客小白月赛35 J.溪染的优惠券(贪心01背包)

本文介绍了一种针对有限物品排序的背包问题解决方案,不同于标准的01背包,它考虑了物品使用顺序的不确定性。通过ai−bia_i-b_i排序,确保了选择过程的最优性。作者通过反证法证明了这种排序方式的有效性,并给出了C++代码实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LINK

有点像 01 01 01背包,但是又不完全是

原因在于使用的物品有限制,使得物品的使用次序是未知的

这样显然无法扫一遍做 01 01 01背包

如果按照 a i a_i ai排序也是不对的,限制大的不一定先使用

若使用变为 k − b i k-b_i kbi,这样中间错过了许多小型优惠劵,可能先使用中间的才更优

于是想到按照 a i − b i a_i-b_i aibi排序,直接做 01 01 01背包即可.

这样选择物品的顺序满足 a i − b i > a j − b j a_i-b_i>a_j-b_j aibi>ajbj

如果只选择 i , j i,j i,j优惠券中的一个,那么顺序是无所谓的, 01 01 01背包会考虑到

如果需要同时选择 i , j i,j i,j物品,那么按照 i , j i,j i,j的顺序 d p dp dp一定是可行的

反证法

设按照 j , i j,i j,i的顺序选可行得到 k > = a j & & k − b j > = a i k>=a_j\&\&k-b_j>=a_i k>=aj&&kbj>=ai

按照 i , j i,j i,j顺序选优惠券不可行得到 k > = a i & & k − b i < a j k>=a_i\&\&k-b_i<a_j k>=ai&&kbi<aj

我们得到 k > = a i + b j & & k < a j + b i k>=a_i+b_j\&\&k<a_j+b_i k>=ai+bj&&k<aj+bi,也就是 a j + b i > a i + b j a_j+b_i>a_i+b_j aj+bi>ai+bj

而因为 a i − b i > a j − b j a_i-b_i>a_j-b_j aibi>ajbj,移项得到 a i + b j > a j + b i a_i+b_j>a_j+b_i ai+bj>aj+bi

显然矛盾,证毕,不存在这种情况.

也就是说,按照 i , j i,j i,j这种方式排序不会错,直接做 01 01 01背包即可

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+10;
int n,k,vis[maxn],s[maxn],f[maxn];
typedef pair<int,int>p;
p a[maxn];
bool com(p a,p b)
{
	if( a.first-a.second==b.first-b.second )	return a.first<b.first;
	return a.first-a.second>b.first-b.second;
}
int main()
{
	cin >> n >> k;
	for(int i=1;i<=n;i++)	cin >> a[i].first >> a[i].second;
	f[k] = 1;
	sort( a+1,a+1+n,com );
	for(int i=1;i<=n;i++)
	for(int j=a[i].first;j<=k;j++)
		f[j-a[i].second] |= f[j];
	int ans = k;
	for(int i=0;i<=k;i++)
		if( f[i] ){	cout << i; return 0; }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值