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;
}