多重背包
Posted yum20
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多重背包相关的知识,希望对你有一定的参考价值。
Description
有重量和价值分别为 wi ( 1 ≤ wi ≤ 1015 )、vi ( 1 ≤ vi ≤ 1015 ) 的 n (1 ≤ n ≤ 40 )个物品。从这些物品中挑选总重量不超过 C (1 ≤ C ≤ 1015)的物品,求所选挑选方案中价值总和的最大值。
多测试用例。每个测试用例:
第一行是 n 和 C,接下来有 n 行,每行两个正整数,分别是各个物品的 wi 和 vi
每个测试用例输出一行:最大价值。
4 5
2 3
1 2
3 4
2 2
7
有N种物品和容量为V的背包,若第i种物品,容量为v[i],价值为w[i],共有n[i]件。
怎样装才能使背包内的物品总价值最大?
而看到这样的问题,通过对过去的学习反思很容易会联想到01背包,都是给定了每个物品的数量,但只是多重背包不一定是1个,但绝不会是无限个,是有个范围的。
因此一开始我想到的做法就是直接把多重背包转化成01背包来做,直接去把每一种背包的的数量单独开来成为一个个独立的包,再沿用01背包的做法要么取要么不取
而以下便是这种想法我一开始初步的实现代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[2000000];
/*struct Beg{
int w,v,num;
}beg[100005];*/
int w[1500000],v[1500000],num[1500000];
int main(){
int T,n,vi;
scanf("%d",&T);
while(T--){
memset(dp,0,sizeof(dp));
scanf("%d %d",&n,&vi);
for(int i=1;i<=n;i++){
scanf("%d %d %d",&w[i],&v[i],&num[i]);
}
int book;
book=n+1;
for(int i=1;i<=n;i++){
while(num[i]>1){
v[book]=v[i];
w[book]=w[i];
num[i]--;
book++;
}
}
for(int i=1;i<=book;i++){
for(int j=vi;j>=1;j--){
if(j>=w[i])
dp[j]=max(dp[j-w[i]]+v[i],dp[j]);
}
}
printf("%d ",dp[vi]);
}
return 0;}
可当然,由于我对题目的数据的轻视,没有保持足够的严谨性,想着用这样想当然的做法一个暴力水过,这种想法真的很危险,从而不管我如何调试最后得到的是tle,后来才知道每种背包的个数是会达到10000的,而dp过程的for()时间复杂度最危险会是1e6*(1e5-1);可1000ms时候1e9已经非常勉强了,所以必须要优化!降低复杂度,在跟队友的讨论下,便明白到就在于把每种包化为独立的包这个问题上下手,将有限个相同价格的物品转化为不同价格的单个物品,这样大大缩短了复杂度,后来发现其实这其实可以用过位运算二进制的思想去做的
总结:对任何题目都不可以抱着想当然的想法去做,有时候想快完成反而弄巧成拙的,尽量要从时间及内存方面等方面去思考如何更好实现这个代码
#include<bits/stdc++.h>
#include<algorithm>
#include<string>
#define MAX 1000000
int dp[MAX];
int w[10005],v[10005],m[10005];
using namespace std;
int main(void){
int T;
scanf("%d",&T);
while(T--){
int C,n,k=0,t;
memset(dp,0,sizeof(dp));
scanf("%d %d",&n,&C);
for(int i=0;i<n;i++){
scanf("%d %d %d",&w[i],&v[i],&m[i]);
t=1;
if(m[i]>1) //将有限个相同价格的物品转化为不同价格的单个物品
{
while(m[i]>t)
{
w[n+k]=w[i]*t;
v[n+k]=v[i]*t;
m[n+k]=1;
m[i]-=t;
t*=2;
k++;
}
w[i]*=m[i];
v[i]*=m[i];
m[i]=1;
}
}
for(int i=0;i<n+k;i++)
// printf("%d %d
",w[i],v[i]);
for(int j=C;j>=w[i];j--)
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
printf("%d
",dp[C]);
}
return 0;
}
以上是关于多重背包的主要内容,如果未能解决你的问题,请参考以下文章