题意: 有50个盒子, 每个盒子里有10个物品, 物品有价值和花费, 盒子只有花费, 只有买了盒子才能买其中的物品, 问总共花P块钱(P<100000)最多能得到多少价值.
思路:
①一开始不记得有依赖背包, 想起之前写的挖矿的题, 以为可以直接写分组背包, 以下是错误的思路:
对于每个盒子, dfs遍历这个盒子内所有的取法, 然后每个盒子是一个分组, 跑分组背包.
复杂度: dfs后, 每个组的大小1000*分组个数50*背包容量(P)100000→5e9
下面这个思路过了, 但这不是有依赖背包的真正写法....
②因为分组背包每个组只会取1个元素, 所以dfs遍历出的1000个中, 代价大而价值小的是绝对没用的.
然而因为dfs复杂度是2^mi(mi是背包大小)所以这个思路只适合这个题...
②代码:
#include<bits/stdc++.h>
using namespace std;
void debug_out() {
cerr << '\n';
}
template<typename T, typename ...R>
void debug_out(const T &f, const R &...r) {
cerr << f << " ";
debug_out(r...);
}
#define debug(...) cerr << "[" << #__VA_ARGS__ << "]: ", debug_out(__VA_ARGS__);
typedef long long ll;
const int M = 2e5 + 5;
const int inf = 1e9 + 5;
const int mod = 1e9 + 7;
int begn;
int P;
struct item {
int prize, w;
};
struct beg {
int sz, price;
vector<item> v;
} Beg[55];
vector<item> V[55];
void init() {
for (int i = 0; i < begn; i++) {
scanf("%d%d", &Beg[i].price, &Beg[i].sz);
for (int j = 0; j < Beg[i].sz; ++j) {
int a, b;
scanf("%d%d", &a, &b);
Beg[i].v.push_back(item{a, b});
}
}
}
void dfs(int bgnum, int lv, int allp, int allw) {
if (lv == Beg[bgnum].sz) {
for (auto & i : V[bgnum]) {//这里去掉了②中提到的分组中绝对没用的元素
if(i.prize<=allp&&i.w>=allw)
return;
}
V[bgnum].push_back(item{allp, allw});
return;
}
dfs(bgnum, lv + 1, allp + Beg[bgnum].v[lv].prize, allw + Beg[bgnum].v[lv].w);
dfs(bgnum, lv + 1, allp, allw);
}
int dp[M] = {0};
void solve() {
memset(dp, 0, sizeof(dp));
for(int i=0;i<begn;i++){
Beg[i].v.clear();
V[i].clear();
}
for (int i = 0; i < begn; i++) {
dfs(i, 0, Beg[i].price, 0);
}
// for (int i = 0; i < begn; i++) {
// debug(V[i].size());
// }
for (int i = 0; i < begn; ++i) {
for (int j = P; j >= 0; j--) {
for (auto &k : V[i]) {
if (j >= k.prize)
dp[j] = max(dp[j], dp[j - k.prize] + k.w);
}
}
}
int ans = 0;
for (int i = 0; i <= P; ++i) {
ans = max(ans, dp[i]);
}
printf("%d\n", ans);
}
int main() {
while (~scanf("%d%d", &begn, &P)) {
init();
solve();
}
return 0;
}