luogu#P1352 没有上司的舞会

题意:

给出一棵树,编号 \(1\) ~ \(N\) 和每个节点上的快乐值 \(R[i]\) 。如果一个节点的父节点被选中,那么这个节点就不能选了。求最大快乐值。

写博客的时候才注意到输入格式有一条 最后一行输入0 0,貌似没有任何用处

解法:

树形dp 记忆化搜索

\(f[i][j]\) = 以 \(i\) 为根的子树中, \(i\) 取( \(j=1\) )不取( \(j=0\) )的最大值

因为题目没有给出树根,所以得把树根手动求出来。

然后从根部搜索,扫描所有可以到达的点 \(v\)dp(v),则

f[x][1]=max( max( f[x][1], f[v][0]+f[x][1]), f[v][0]);
f[x][0]=max( max( f[x][0], f[v][1]+f[x][0]), max( f[v][1], f[v][0]);
#include<cstdio>
#define N 6005
using namespace std;
struct Edge{int next,son;}edge[N];
int n,r[N],n_e,head[N],root,f[N][2];
bool rt[N];

inline int max(const int x,const int y);
int dp(int x);
inline void addedge(int fa,int son);
void init();
int main()
{
	init();
	dp(root);
	printf("%d",max(f[root][1],f[root][0]));
	return 0;
}	
void init()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&f[i][1]);
	for(int i=1;i<n;i++)
	{
		int l,k;
		scanf("%d%d",&l,&k);
		rt[l]=1;
		addedge(k,l);
	}
	for(int i=1;i<=n;i++)
		if(!rt[i])
		{
			root=i;
			break;
		}
}
inline void addedge(int fa,int son)
{
	edge[++n_e].next=head[fa];
	edge[n_e].son=son;
	head[fa]=n_e;
}
int dp(int x)
{
	for(int i=head[x];i;i=edge[i].next)
	{
		int v=edge[i].son;
		dp(v);
		f[x][1]=max(max(f[x][1],f[v][0]+f[x][1]),f[v][0]);
		f[x][0]=max(max(f[x][0],f[v][1]+f[x][0]),max(f[v][1],f[v][0]));
	}
	
}
inline int max(const int x,const int y)
{
	return x>y?x:y;
} 

posted @ 2019-10-21 21:50  nenT  阅读(87)  评论(0)    收藏  举报