UVa-12325宝箱

https://blog.csdn.net/jc514984625/article/details/51803842
题目大意:

你有一个体积为N的箱子和两种数量无限的宝物。宝物1的体积为S1,价值为V1;宝物2的体积为S2,价值为V2。输入均为32位带符号的整数。你的任务是最多能装多少价值的宝物?

我首先想到完全背包,后来RE才发现数组开不下,要用枚举,参看了上面网址的这篇博客。

方法:其实也没那么不好想,关键是要冷静下来一步步分析,如何降低枚举的数量。首先立马想到的肯定是性价比高的先装,但问题是会有剩余空间,使得这样的贪心策略并不是最优的。假设我们现在已经满足s1v2<=s2v1,也就是说物品1性价比不会比物品2的小。那么设最终物品1选n1件,物品2选n2件我们得到的等式就是ans=n1v1+n2v2。此时显然有物品2的数量不会超过s1,(否则这s1个物品2的空间放物品1的价值为s2*v1更优),同时n2自身不会超过n/s2,对于s1<=s2的情况下显然复杂度在sqrt(n)之下;对于s1>s2时显然只能枚举物品1的数量了,首先由于物品1性价比高,所以我们不妨先全选了,然后再枚举要拿出多少物品1放物品2可取到最优解,那么显然同样我们能拿出的物品数不会超过s2,同时总的拿出的物品数不会大于n/s1,故复杂度仍然在sqrt(n)之下。这样问题就解决了。
本题有个有个降低枚举量的方法,即判断S1,S2的大小关系后再进行枚举但当S1,S2都很小的则用到下面一种枚举方法:

对于宝物1和2,当所占体积为S1S2时,分别能够提供的价值为S2V1和S1V2,我们便可以根据两者的大小关系判断选哪一种物品,如果S2V1>=S1*V2,则我们可以得出宝物的数量最多为S1-1,因为如果我们选了S1件宝物2,则我们完全可以用S2件宝物1去代替,而且我们获得价值会更大。因此每次可以枚举min(S1-1,cnt2)或者min(S2-1,cnt1)便可以得出答案。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

int main()
{
	int T; scanf("%d\n",&T);
	int kase = 1; 
	int n,s1,v1,s2,v2;
	while( T-- ) {
		
		scanf("%d %d %d %d %d",&n,&s1,&v1,&s2,&v2 );
		if( s1>s2 ) {
			swap( s1,s2); swap(v1,v2);
		}
		LL value = 0;
		if( n/s2>=65536 ) {
			for( LL i=0; i<=s1; ++i ) 
				value = max( value , i*v2 + (n-i*s2)/s1 * v1 );
			for( LL i=0; i<=s2; ++i ) 
				value = max( value , i*v1 + (n-i*s1)/s2 * v2 );
		}
		else {
			for( LL i=0; i*s2<=n; ++i ) 
				value = max( value , i*v2 + (n-i*s2)/s1 * v1 );
		}
		printf("Case #%d: %lld\n",kase++,value );
	}
	return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值