背包问题

一、01背包

给你一个容量为W的书包,一些体积(重量)为wi,价值为vi的东西,每个东西只有放与不放两种选择。

经典例题:HDU 2602

http://acm.hdu.edu.cn/showproblem.php?pid=2602

题解:背包容量为V,有N件物品,已知每件物品的体积(重量)与价值,求最大价值。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<stack>
 7 #define ll long long
 8 using namespace std;
 9 const int N = 1005;
10 const int mod = 1e9 + 7;
11 int dp[N][N], v[N], w[N];
12 
13 int main()
14 {
15     std::ios::sync_with_stdio(false);
16     int T;
17     cin >> T;
18     while(T--){
19         int n, V;
20         memset(dp, 0, sizeof(dp));
21         
22         cin >> n >> V;
23         for(int i = 1; i <= n; i++){
24             cin >> v[i];
25         }
26         for(int i = 1; i <= n; i++){
27             cin >> w[i];
28         }
29         //dp[i][j]表示在前i个物品中,总重量不超过j的总价值
30         for(int i = 1; i <= n; i++){
31             for(int j = 0; j <= V; j++){//顺序  从0到V
32                 if(j < w[i]){
33                     dp[i][j] = dp[i - 1][j];//放不下该物品,价值不变
34                 }
35                 else {
36                     dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - w[i]] + v[i]);//放得下,求最大
37                 }
38             }
39         }
40         
41         cout << dp[n][V] << endl;
42     }
43     return 0;
44 }

 

二、完全背包

给你一个书包,和一些物品,物品价值和体积(重量)已知,数量无数,可以随便放。

经典例题:HDU 1114

http://acm.hdu.edu.cn/showproblem.php?pid=1114

题解:一个存钱罐重a,装满钱重b,给你一些硬币的价值和重量,求最大价值。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #define ll long long
 8 using namespace std;
 9 
10 const int N = 10005;
11 const int inf = 0x3f3f3f3f;
12 
13 int main()
14 {
15     int T;
16     cin >> T;
17     
18     while(T--)
19     {
20         int a, b, m;
21         int dp[N], v[N], w[N];//dp[j]表示在重量不超过j的情况下的最大价值
22         memset(dp, inf, sizeof(dp));
23         dp[0] = 0;
24         
25         cin >> a >> b >> m;
26         
27         for(int i = 0; i < m; i++)
28         {
29             cin >> v[i] >> w[i];
30         }
31         
32         for(int i = 0; i < m; i++)
33         {
34             for(int j = w[i]; j <= b - a; j++)
35             {
36                 dp[j] = min(dp[j], dp[j - w[i]] + v[i]);
37             }
38         }
39         
40         if(dp[b - a] == inf)
41             cout << "This is impossible." << endl;
42         else
43             cout << "The minimum amount of money in the piggy-bank is " << dp[b - a] << '.' << endl;
44         
45     }
46     return 0;
47 }

 

三、多重背包

给你一个书包,物品的价值和重量已知,每种物品的数量有限定且不一样。

可以转化成01背包和完全背包问题求解。

经典例题:HDU 2844

http://acm.hdu.edu.cn/showproblem.php?pid=2844

题解:给你几种硬币的价值和数量,求他们能组成多少种价值。

代码:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 #include<algorithm>
 6 #include<queue>
 7 #define ll long long
 8 using namespace std;
 9 
10 const int N = 100005;
11 const int inf = 0x3f3f3f3f;
12 int dp[N];
13 int v[N], num[N];
14 
15 void CompletePack(int v, int w, int bag) //完全背包 
16 {
17     for(int i = w; i <= bag; i++) // 顺序 
18     {
19         dp[i] = max(dp[i], dp[i - w] + v);
20     }
21 }
22 
23 void ZeroOnePack(int v, int w, int bag) //01背包 
24 {
25     for(int i = bag; i >= w; i--) //逆序  
26     {
27         dp[i] = max(dp[i], dp[i - w] + v);
28     }
29 }
30 
31 void MultiplePack(int v, int w, int count, int limit)//多重背包 
32 {
33     if(w * count >= limit)//背包足够大,转化为完全背包问题 
34     {
35         CompletePack(v, w, limit);
36         return;
37     }
38     else//转化为01背包 
39     {
40         int k = 1;
41         while(k <= count)
42         {
43             ZeroOnePack(k * v, k * w, limit);
44             count -= k;
45             k *= 2;//采用二进制思想 
46         }
47         ZeroOnePack(count * v, count * w, limit);
48         return;
49     }
50 }
51 
52 int main()
53 {
54     std::ios::sync_with_stdio(false); 
55 
56     int n, m;
57     while(cin >> n >> m && n && m)
58     {
59         memset(dp, -inf, sizeof(dp));
60         dp[0] = 0;
61         
62         for(int i = 0; i < n; i++)
63         {
64             cin >> v[i];
65         }
66         for(int i = 0; i < n; i++)
67         {
68             cin >> num[i];
69         }
70         
71         for(int i = 0; i < n; i++)
72         {
73             MultiplePack(v[i], v[i], num[i], m);
74         }
75         
76         int ans = 0;
77         for(int i = 1; i <= m; i++)
78         {
79             if(dp[i] > 0)
80                 ans++;
81         }
82         
83         cout << ans << endl;
84         
85     }
86     return 0;
87 }

 

posted @ 2019-08-15 17:00  小夯货  阅读(156)  评论(0编辑  收藏  举报