【题解】P1352

时间:2021-08-24
本文章向大家介绍【题解】P1352,主要包括【题解】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;
}

原文地址:https://www.cnblogs.com/mango13/p/Solution-P1352.html