码迷,mamicode.com
首页 > 其他好文 > 详细

多重背包

时间:2018-09-03 12:10:30      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:范围   ring   script   inpu   des   怎样   can   学习   一个个   

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\n",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\n",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\n",dp[C]);
   }
   return 0;
}

 

多重背包

标签:范围   ring   script   inpu   des   怎样   can   学习   一个个   

原文地址:https://www.cnblogs.com/Yum20/p/9577578.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!