1722: [Usaco2006 Mar] Milk Team Select 产奶比赛
https://www.lydsy.com/JudgeOnline/problem.php?id=1722
分析:
f[u][i][0/1]表示子树u中,有i对相邻的点,最大和是多少。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<iostream>
#include<cctype>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define fi(s) freopen(s,"r",stdin);
#define fo(s) freopen(s,"w",stdout);
using namespace std;
typedef long long LL; inline int read() {
int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
const int INF = 1e9; int f[N][N][], g[N][];
int head[N], nxt[N], to[N], siz[N], w[N], fa[N];
int n, x, En; void add_edge(int u,int v) {
++En; to[En] = v; nxt[En] = head[u]; head[u] = En;
} void dfs(int u) {
siz[u] = ;
f[u][][] = w[u];
f[u][][] = ;
for (int i=head[u]; i; i=nxt[i]) {
int v = to[i];
dfs(v);
siz[u] += siz[v];
for (int j=; j<=siz[u]-; ++j) // 相邻的
for (int k=,lim=min(j, siz[v]-); k<=lim; ++k) { // 子树中相邻的
g[j][] = max(g[j][], f[u][j - k][] + max(f[v][k][], f[v][k][]));//cerr << g[j][0] << "\n";
if (j - k >= ) g[j][] = max(g[j][], f[u][j - k][] + f[v][k][]); //cerr << g[j][1] << "\n";;
if (j - k - >= ) g[j][] = max(g[j][], f[u][j - k - ][] + f[v][k][]);// cerr << g[j][1] << "\n";; }
for (int j=n; j>=; --j)
f[u][j][] = g[j][], f[u][j][] = g[j][], g[j][] = g[j][] = -INF;
}
}
int main() {
n = read(), x = read();
memset(f, -0x3f, sizeof(f));
memset(g, -0x3f, sizeof(g)); // 把g[0]初始化了!!!
// for (int i=1; i<=n; ++i) g[i][0] = g[i][1] = -INF;
for (int i=; i<=n; ++i) {
w[i] = read(), fa[i] = read();
add_edge(fa[i], i);
}
dfs();
for (int i=n; i>=; --i) {
if (f[][i][] >= x) { cout << i; return ; }
}
cout << -;
return ;
}