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