题意与分析
学习本题的时候遇到了一定的困难。看了题解才知道这是二重背包。本题的实质是二重完全背包。
二维费用的背包问题是指:对于每件物品,具有两种不同的费用,选择这件物品必须同时付出这两种代价:对于每种代价都有一个可付出的最大值(背包容量)。问怎样选择物品可以得到最大的价值。
设第i件物品的两种代价分别为
ai
a
i
和
bj
b
j
,两种代价可付出的最大值(两种背包容量)分别为
V
V
和,物品的价值为
wi
w
i
,那么我们可以改进原来的状态转移方程,则定义
dp[i][j][k]
d
p
[
i
]
[
j
]
[
k
]
为选前i件物品,前两个代价分别为j与k的最大价值,则:
这是01背包的公式。而我们又知道,对于完全背包,仍然可以从01背包的公式推出(原因见前面的题解blog),只需改变推的顺序就可以了。
顺便补充一下多重背包的方法:拆分物品,具体见之后做的题目。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#define MP make_pair
#define PB push_back
#define fi first
#define se second
#define ZERO(x) memset((x), 0, sizeof(x))
#define ALL(x) (x).begin(),(x).end()
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define per(i, a, b) for (int i = (a); i >= (b); --i)
#define QUICKIO \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0);
using namespace std;
template<typename T>
T read()
{
T tmp; cin>>tmp;
return tmp;
}
int main()
{
int n,m,k,s,w[105],v[105];
while(cin>>n>>m>>k>>s)
{
rep(i,1,k) cin>>v[i]>>w[i];
int dp[105][105]; ZERO(dp);
int ans=-0x3f3f3f3f;
rep(i,1,k)
rep(j,1,s)
{
rep(p,w[i],m)
{
dp[j][p]=max(dp[j][p],dp[j-1][p-w[i]]+v[i]);
if(dp[j][p]>=n && (m-p)>ans)
{
ans=m-p;
}
}
}
if(ans==-0x3f3f3f3f)
cout<<-1<<endl;
else
cout<<ans<<endl;
}
return 0;
}