【DP】没有上司的舞会(简单树形DP)

该文章介绍了一个图论问题,给定一棵有根树,每个节点有相应权值,选取节点时遵循父亲节点被选则所有儿子节点不能被选的原则。文章通过动态规划(dp)解决,定义了dp[x][1](选x节点)和dp[x][0](不选x节点)的状态,并通过深度优先搜索(dfs)遍历树来计算最大权值和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

没有上司的舞会 - 洛谷

题意,给定一颗有根树,每个节点有一个权值,如果取父亲节点的权值,那么所有儿子节点的权值不能取。试规划一种节点选取方案,使得取到的节点权值和最大,只要求给出最大值。

容易想到:父亲选了。儿子一定不能选。父亲没选,儿子可以选,也可以不选。(因为有负权值)

用dp[x][1]表示选了x节点后,x和其所有子孙的合规选法的最大权值和。

用dp[x][0]表示没选x节点,其所有子孙的合规选法的答案权值和。

dp[x][1]=\sum(dp[x的儿子][0])+自己的权值;

dp[x][0]=\sum(max(dp[x的儿子][1],dp[x的儿子][0]));

状态的定义一定要明确好。不然父亲,儿子,孙子,容易搞晕的。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
int n;
int dp[6007][7],a[6007],vis[6007];
vector<int>g[6007];
int dfs(int x){
	vis[x]=1;
	dp[x][1]=a[x]; 
	int val=0;
	rep(i,0,g[x].size()-1){
		int v=g[x][i];
		if(vis[v]==1)continue;
		dfs(v);
		dp[x][1]+=dp[v][0];
		dp[x][0]+=max(dp[v][0],dp[v][1]);		
	} 
	
}
int main(){
	cin>>n;
	rep(i,1,n)cin>>a[i];
	rep(i,1,n-1){
		int x,y;
		cin>>x>>y;
		g[x].push_back(y);
		g[y].push_back(x); 
		vis[x]=1;
	}
	int root;
	rep(i,1,n)if(vis[i]==0)root=i;
	memset(vis,0,sizeof(vis));
	dfs(root);
	cout<<max(dp[root][1],dp[root][0]);
	//cout<<endl<<dp[3][0]; 
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值