树形DP没有上司的舞会

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形DP没有上司的舞会相关的知识,希望对你有一定的参考价值。

  • 博客主页: https://blog.csdn.net/qq_50285142
  • 欢迎点赞👍收藏✨关注❤留言 📝 如有错误,敬请指正
  • 🎈虽然生活很难,但我们也要一直走下去🎈

原题链接

题意:
某大学有 n 个职员,编号为 1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r i r_i ri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
求邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

思路:
首先这n个用户的关系可以构成一棵树,只要选中父节点,那么父节点的子节点就不可以选,也就是父节点和子节点必选其一
树形结构求最优解考虑树形DP
节点标号可以使用数组进行存储
状态表示:状态表示类似于状态机模型
f [ i ] [ 1 ] f[i][1] f[i][1]表示选中节点i的最大值
f [ i ] [ 0 ] f[i][0] f[i][0]表示不选节点i的最大值
状态转移:
当前节点不选中可以由子节点不选中和子节点选中转移过来
f [ u ] [ 0 ] + = m a x ( f [ v ] [ 1 ] , f [ v ] [ 0 ] ) f[u][0] += max(f[v][1],f[v][0]) f[u][0]+=max(f[v][1],f[v][0])
而当前节点选中只能由子节点不选中转移过来
f [ u ] [ 1 ] + = f [ v ] [ 0 ] f[u][1] += f[v][0] f[u][1]+=f[v][0]

本题使用链式前向星存储树,做树形DP时,每次先对当前的节点的权值操作,这样 f [ i ] [ 1 ] f[i][1] f[i][1]就可以进行初始化了,这样会先递归到叶子节点对叶子结点进行操作,然后再对其父节点进行操作。

首先我们需要找到根节点,我们用有向图来存储树,然后标记子节点是否出现,这样没有出现的节点一定是根节点


#include<bits/stdc++.h>
using namespace std;
const int N = 6e3+5;

int h[N],w[N],ne[N],idx,e[N],n;
int f[N][2];
bool vis[N];

void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dp(int u)
{
	f[u][1] += w[u];
	for(int i=h[u];~i;i=ne[i])
	{
		int v = e[i];
		dp(v);
		f[u][0] += max(f[v][1],f[v][0]);
		f[u][1] += f[v][0];
	}
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++) cin>>w[i];
	memset(h,-1,sizeof h);
	for(int i=1;i<n;i++)
	{
		int u,v;
		cin>>u>>v;
		vis[u]=true;
		add(v,u);
	}
	int u;
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			u = i;
			break;
		}
	}
	dp(u);
	cout<<max(f[u][0],f[u][1])<<'\\n';
	return 0;
} 

往期优质文章推荐

以上是关于树形DP没有上司的舞会的主要内容,如果未能解决你的问题,请参考以下文章

P1352 没有上司的舞会——树形DP入门

[luogu]P1352 没有上司的舞会[树形DP]

树形DP 没有上司的舞会

luogu1352没有上司的舞会 - 树形dp

poj2342 没有上司的舞会 树形dp基础

P1352 没有上司的舞会+P1122 最大子树和(树形DP入门)