「暑期训练」「基础DP」FATE(HDU-2159)

题意与分析

学习本题的时候遇到了一定的困难。看了题解才知道这是二重背包。本题的实质是二重完全背包。
二维费用的背包问题是指:对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种代价:对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。
设第i件物品的两种代价分别为$a_i$和$b_j$,两种代价可付出的最大值(两种背包容量)分别为$V$和$U$,物品的价值为$w_i$,那么我们可以改进原来的状态转移方程,则定义$dp[i][j][k]$为选前i件物品,前两个代价分别为j与k的最大价值,则:
$$dp[i][j][k]=max(dp[i-1][j-a[i]][k-b[i]]+w[i],dp[i-1][j][k])$$

这是01背包的公式。而我们又知道,对于完全背包,仍然可以从01背包的公式推出(原因见前面的题解blog),只需改变推的顺序就可以了。
顺便补充一下多重背包的方法:拆分物品,具体见之后做的题目。

代码

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <vector>
 5 #define MP make_pair
 6 #define PB push_back
 7 #define fi first
 8 #define se second
 9 #define ZERO(x) memset((x), 0, sizeof(x))
10 #define ALL(x) (x).begin(),(x).end()
11 #define rep(i, a, b) for (int i = (a); i <= (b); ++i)
12 #define per(i, a, b) for (int i = (a); i >= (b); --i)
13 #define QUICKIO                  
14     ios::sync_with_stdio(false); 
15     cin.tie(0);                  
16     cout.tie(0);
17 using namespace std;
18 
19 template<typename T>
20 T read()
21 {
22     T tmp; cin>>tmp;
23     return tmp;
24 }
25 
26 int main()
27 {
28     int n,m,k,s,w[105],v[105];
29     while(cin>>n>>m>>k>>s)
30     {
31         rep(i,1,k) cin>>v[i]>>w[i];
32         int dp[105][105]; ZERO(dp);
33         int ans=-0x3f3f3f3f;
34         rep(i,1,k)
35             rep(j,1,s)
36             {
37                 rep(p,w[i],m)
38                 {
39                     dp[j][p]=max(dp[j][p],dp[j-1][p-w[i]]+v[i]);
40                     if(dp[j][p]>=n && (m-p)>ans)
41                     {
42                         ans=m-p;
43                     }
44                 }
45             }
46         if(ans==-0x3f3f3f3f)
47             cout<<-1<<endl;
48         else
49             cout<<ans<<endl;
50     }
51     return 0;
52 }
点我看高清美少女
如非注明,原创内容遵循GFDLv1.3发布;其中的代码遵循GPLv3发布。
原文地址:https://www.cnblogs.com/samhx/p/hdu-2159.html