发现商品间的关系显然是棵树,所以做树上背包。
发现商品的价格都很高不能放在状态里,而价值都是1,所以转换维度。
定义\(dp[u][j][0/1]\)为在\(u\)的子树中选出\(j\)个物品所需要的最小价格,其中0代表不用优惠券买u,1代表用优惠券买u。
转移:
答案为 \(max(i)\) 满足 \(dp[1][i][1] <= b\)
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
char buf[1 << 20], *p1 = buf, *p2 = buf;
char getc() {
if (p1 == p2) {
p1 = buf, p2 = buf + fread(buf, 1, 1 << 20, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline int read() {
int s = 0, w = 1;
char c = getc();
while (c < ‘0‘ || c > ‘9‘) { if (c == ‘-‘) w = -1; c = getc(); }
while (c >= ‘0‘ && c <= ‘9‘) s = s * 10 + c - ‘0‘, c = getc();
return s * w;
}
const int maxn = 5e3 + 5;
int n, B;
struct edge {
int nex, to;
}e[maxn * maxn];
int head[maxn], tot;
void Add(int u, int v) {
e[++tot] = (edge) { head[u], v };
head[u] = tot;
}
int dp[maxn][maxn][3];
int siz[maxn], c[maxn], d[maxn];
void Dfs(int u) {
siz[u] = 1;
for (int i = head[u]; i; i = e[i].nex) {
int v = e[i].to;
Dfs(v);
siz[u] += siz[v];
}
return;
}
void DP(int u) {
for (int i = head[u]; i; i = e[i].nex) {
int v = e[i].to;
DP(v);
for (int j = siz[u] - siz[v]; j >= 0; j--) {
for (int k = siz[v]; k >= 0; k--) {
dp[u][j + k][1] = min(dp[u][j + k][1], dp[u][j][1] + min(dp[v][k][1], dp[v][k][0]));
dp[u][j + k][0] = min(dp[u][j + k][0], dp[u][j][0] + dp[v][k][0]);
}
}
}
}
int main() {
n = read(), B = read();
int fa;
for (int i = 1; i <= n; i++) {
if (i == 1) {
c[i] = read();
d[i] = read();
}
else {
c[i] = read();
d[i] = read();
fa = read();
Add(fa, i);
}
}
Dfs(1);
memset(dp, 0x3f, sizeof dp);
for (int i = 1; i <= n; i++) {
dp[i][1][1] = c[i] - d[i];
dp[i][1][0] = c[i];
dp[i][0][0] = 0;
}
DP(1);
int ans;
for (int i = 1; i <= n; i++) {
if (dp[1][i][1] <= B)
ans = i;
}
printf("%d\n", ans);
return 0;
}
原文:https://www.cnblogs.com/Zfio/p/13726289.html