ACM_01背包2

背包4

Time Limit: 2000/1000ms (Java/Others)

Problem Description:

有n个重量和价值分别为Wi,Vi的物品,现从这些物品中挑选出总量不超过W的物品,求所有方案中价值总和的最大值。

Input:

输入包含多组测试用例,每一例的开头为两位整数 n、W;接下来有 n 行,每一行有两位整数 Wi、Vi
其中:
1<=n<=100
1<=W<=1000,000,000(10^9)
1<=Wi<=10,000,000(10^7)   
1<=Vi<=100。 

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 }

猜你喜欢

转载自www.cnblogs.com/acgoto/p/8999745.html