「暑期训练」「基础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发布。