01背包变形

传送门

现有 N 个物品,序号分别为 1, 2, ... , N。对于每个 i (1 ≤ i ≤ N),物品 i 有一个体积 wi 和一个价值 vi

小明想在这 N 个物品中选取一些放到背包里带回家。已知背包的容积为 W,这意味着所带物品的总体积不能超过 W

求出小明可以带回家的物品总价值可能的最大值。

Constraints

 

  • 输入的所有数值均为整数。
  • 1 ≤ N ≤ 100
  • 1 ≤ W ≤ 109
  • 1 ≤ wi ≤ W
  • 1 ≤ vi ≤ 103

Input

 

标准输入格式如下:

N W
w1 v1
w2 v2
:
wN vN

Output

 

输出小明可以带回家的物品总价值可能的最大值。

Sample Input 1

 

3 8
3 30
4 50
5 60

Sample Output 1

 

90

把物品 1 和物品 3 带回家,此时它们的总体积为 3 + 5 = 8,总价值为 30 + 60 = 90 最大。

Sample Input 2

 

1 1000000000
1000000000 10

Sample Output 2

 

10

Sample Input 3

 

6 15
6 5
5 6
6 4
6 6
3 5
7 2

Sample Output 3

 

17

物品 2, 4 和 5 可以被带回家,此时它们的总体积为 5 + 6 + 3 = 14,总价值为 6 + 6 + 5 = 17

如果按照普通的01背包的板子的复杂的是O(n*w),但是这个题的1 ≤ W ≤ 109,所以肯定会超时

那怎么办呢,注意这个题的每一个体积1 ≤ vi ≤ 103,就是说总体积不会超过1e5,

然后你设置一个dp[i],为价值为i的最小体积,然后从sumv到1判断dp[i]是否小于W

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+100;
ll n,w[maxn],v[maxn];
ll dp[maxn];
ll sum=0;
ll W;
int main(){
    cin>>n>>W;
    for(int i=1;i<=n;i++){
        cin>>w[i]>>v[i];
        sum+=v[i]; 
    }
    memset(dp,0x3f3f3f3f,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++){
        for(int j=sum;j>=v[i];j--){
            dp[j]=min(dp[j],dp[j-v[i]]+w[i]); 
        }
    } 
    for(int i=sum;i>=1;i--){
        if(dp[i]<=W){
            cout<<i<<endl;
            break;
        } 
    }
} 
原文地址:https://www.cnblogs.com/lipu123/p/14505611.html