【题解】P1352
P1352 没有上司的舞会
\(\text{Description}\)
有一棵由 \(n\) 个节点构成的有根树,每个节点有一个权值 \(r_i\),现在要从中选出一些节点,但是不能同时选择一个节点和他的父节点。请选择一些点使得他们的权值和最大,求最大的权值和。
\(\text{Solution}\)
要使权值和最大,首先考虑树上贪心和树形 \(\rm DP\),又发现父节点的选择直接导致子节点,父节点有选和不选两种,所以我们用树形 \(\rm DP\)。设 \(dp_{u,0}\) 表示节点 \(u\) 不选时的最大权值和,\(dp_{u,1}\) 表示节点 \(u\) 选时的最大权值和。对于 \(u\) 的一个子节点 \(v\):
初始化 \(dp_{u,0}=0,dp_{u,1}=r_u\)。
那么 \(u\) 不选时 \(v\) 可以选或不选,\(dp_{u,0}\gets dp_{u,0}+\max\{dp_{v,0},dp_{v,1}\}\);
\(u\) 选时 \(v\) 一定不能选,\(dp_{u,1}\gets dp_{u,1}+dp_{v,0}\)。
答案就是 \(\max\{dp_{root,0},dp_{root,1}\}\)。
\(\text{Code}\)
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 6e3 + 5;
int cnt;
int head[MAXN], r[MAXN], dp[MAXN][2], in[MAXN];
struct edge
{
int to, nxt;
}e[MAXN];
void add(int u, int v)
{
e[++cnt] = edge{v, head[u]};
head[u] = cnt;
}
void dfs(int u, int fa)
{
dp[u][1] = r[u];
for (int i = head[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if (v == fa)
{
continue;
}
dfs(v, u);
dp[u][0] += max(dp[v][0], dp[v][1]);
dp[u][1] += dp[v][0];
}
}
int main()
{
int n, rt;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
{
scanf("%d", r + i);
}
for (int i = 1; i < n; i++)
{
int u, v;
scanf("%d%d", &v, &u);
add(u, v);
in[v]++;
}
for (int i = 1; i <= n; i++)
{
if (!in[i]) //找根节点
{
dfs(rt = i, 0);
break;
}
}
printf("%d\n", max(dp[rt][0], dp[rt][1]));
return 0;
}