多重背包

Posted yum20

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多重背包相关的知识,希望对你有一定的参考价值。

Description

有重量和价值分别为 wi ( 1 ≤ wi ≤ 1015 )、vi ( 1 ≤ vi ≤ 1015 ) 的 n (1 ≤ n ≤ 40 )个物品。从这些物品中挑选总重量不超过 C (1 ≤ C ≤ 1015)的物品,求所选挑选方案中价值总和的最大值。

Input

多测试用例。每个测试用例:

第一行是 nC,接下来有 n 行,每行两个正整数,分别是各个物品的 wivi

Output

每个测试用例输出一行:最大价值。

Sample Input

4 5
2 3
1 2
3 4
2 2

Sample Output

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

 

















































































以上是关于多重背包的主要内容,如果未能解决你的问题,请参考以下文章

动态规划问题3--多重背包

蒟蒻吃药计划-治疗系列 #round4 多重背包+混合背包代码存放

解题报告:hdu2191汶川地震 - 多重背包模板

POJ 3260 多重背包+完全背包

01背包模板全然背包 and 多重背包(模板)

01背包+完全背包+多重背包+单调队列