背包4
Time Limit: 2000/1000ms (Java/Others)
Problem Description:
有n个重量和价值分别为Wi,Vi的物品,现从这些物品中挑选出总量不超过W的物品,求所有方案中价值总和的最大值。
Output:
输出为一行,即所有方案中价值总和的最大值。
Sample Input:
4 5
2 3
1 2
3 4
2 2
4 10000000
2 3
2 2
3 3
1 2
Sample Output:
7
10
解题思路:相比01背包之前的问题,只是修改了限制条件的大小,此前求解这一问题的时间复杂度是O(nW),但是对于这一问题,W最大为10^9,显然使用之前的方法会超时。但是可以发现,相比较重量而言,价值的范围比较小,因此换种角度可以解决此题。之前的方法中,dp[i]是求解当前重量i不超过总重量W下的最大价值,而这次的dp[i][j]表示从前i个物品中挑选价值总和为j时总重量的最小值(不存在时就是一个充分大的INF)。
状态转移方程:dp[i+1][j]=min(dp[i][j],dp[i][j-v[i]]+w[i])。
AC代码:
1 #include<bits/stdc++.h>
2 using namespace std;
3 #define MAX_n 100
4 #define MAX_v 100
5 const int INF = 0x3f3f3f3f;
6 int w[MAX_n+1],v[MAX_n+1],dp[MAX_n+1][MAX_n*MAX_v+1];
7 int main()
8 {
9 int n,W;
10 while(cin>>n>>W){
11 fill(dp[0],dp[0]+MAX_n*MAX_v+1,INF);
12 dp[0][0]=0;
13 for(int i=0;i<n;++i)
14 cin>>w[i]>>v[i];
15 for(int i=0;i<n;++i){
16 for(int j=0;j<=MAX_n*MAX_v;++j){
17 if(j<v[i])dp[i+1][j]=dp[i][j];
18 else dp[i+1][j]=min(dp[i][j],dp[i][j-v[i]]+w[i]);
19 }
20 }
21 int res=0;
22 for(int i=0;i<=MAX_n*MAX_v;++i)
23 if(dp[n][i]<=W)res=i;
24 cout<<res<<endl;
25 }
26 return 0;
27 }