Anniversary party---树形dp

题目链接
https://vjudge.z180.cn/problem/POJ-2342
题目大意:公司安排一场聚会,你可以安排聚会有哪些人参加,公司里有上下级关系,每个员工都有一个权值(可正可负),但是聚会安排有一个硬性要求,就是,一个员工和他的直接上司不能同时参加聚会,你的任务是,使得参加聚会的人的权值之和尽可能的大,输出最大是多少.

输入:第一行一个整数N,代表公司员工人数
接下来N行,每行一个整数wi,表示第i名员工的权值
接下里N-1行,每行两个整数L,K,表示K是L的直接上司

分析:首先根据关系建立一个树形图,设dp数组为dp[u][2],dp[u][0],表示u这个员工不参加聚会,那么此时他的所有直接下属都可以参加聚会或者不参加状态转移方程dp[u][0] = sum(max(dp[v][0],dp[v][1])),v是u的子节点(也就是直接下属),dp[u][1]表示u这个员工参加聚会,此时他的直接下属就不能参加聚会状态转移方程dp[u][1] = sum(dp[v][0])

建图可以采用链式前向星,不懂的可以现学一下,很简单链式前向星详解

AC代码:

#include<iostream>
#include<cstring>
using namespace std;
const int Maxn = 1e4+10;
/*链式前向星*/
struct Edge
{
	int v;
	int next;
}edge[Maxn];
int head[Maxn];
int f[Maxn][2];//f[i][1],表示选择当前节点时的最大权值,f[i][0]表示不选当前节点时的最大权值 
int w[Maxn];
bool vis[Maxn];//记录节点是否有父亲,找根节点 
int sz[Maxn];//记录以u为根结点的树有多少个子节点 
int cnt = 0;
/*链式前向星建图*/
void build(int u,int v)
{
	edge[++cnt].v = v;
	edge[cnt].next = head[u];
	head[u] = cnt;
	return ;
}
void dfs(int u)
{
	f[u][1] = w[u];
	f[u][0] = 0;
	sz[u] = 1;
	for(int i=head[u];i!=-1;i=edge[i].next)
	{
		dfs(edge[i].v);
		f[u][1] +=f[edge[i].v][0];
		f[u][0] +=max(f[edge[i].v][0],f[edge[i].v][1]);
	}
	return ;
}
int main()
{
	memset(head,-1,sizeof(head));
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    int u,v;
	while(cin>>v>>u)
	{
		if(!v&&!u) break;
		vis[v] = true;
		build(u,v);
	}
	int node;
	for(int i=1;i<=n;i++)
	{
		if(!vis[i])
		{
			node = i;
			break;
		}
	}
    dfs(node);
    cout<<max(f[node][1],f[node][0]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值