【树形dp】洛谷P1352 没有上司的舞会

目录

1. 题目描述

2. 思路描述 :树形dp

3. 代码解释:

1)确定根节点root:

2)dfs

4. 完整代码:


1. 题目描述

没有上司的舞会 - 洛谷

2. 思路描述 :树形dp

采用树形动态规划(DP)的方法,从叶子节点向上搜索。首先,寻找树的根节点,然后通过DFS(深度优先搜索)遍历树的结构。在DFS过程中,更新每个节点的两种状态(选择或不选择),以计算最大幸福值。最终,输出根节点的最大幸福值作为答案。

1. 我们有两种搜索方法,第一种是从根节点向下搜到子节点,第二种是从子节点向上搜到根节点

如果从上往下搜,我们无法确定他被选或者不被选的f[][],无法写出表达式,而从下往上搜可以,

所以我们从下向上搜

2. 

3. 代码解释:

1)确定根节点root:

这道题中,并没有提及这棵树的根节点是什么,所以我们要找到根节点,便于最后输出

在之前我们假设每个点 i 的父节点是他自己,后面建图时改为正确的根节点

然后搜索,如果他的父节点还是自己,那他就是根节点root

建边纯纯模板,先不放部分代码

int main()
{
	int l,k;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>r[i];
		fa[i]=i;
	}
	for(int i=1;i<=n-1;i++)
	{
		cin>>l>>k;
		add(k,l);
		fa[l]=k;
	}
	for(int i=1;i<=n;i++)
	{
		if(fa[i]==i) 
		{
			root=i;
			break;
		}
	}
	dfs(root);
	int ans=0;
	ans=max(f[root][1],f[root][0]);
	cout<<ans;
}

2)dfs

根据思路图,直接写

void dfs(int t)
{
	f[t][1]=r[t];
	for(int i=head[t];i;i=ne[i])
	{
		int g=e[i];
		dfs(g);
		f[t][1]+=f[g][0];
		f[t][0]+=max(f[g][1],f[g][0]);
	}
}

要注意的是,如果要选择点t,先把f[t][1]加上t点的happy值

4. 完整代码:

#include<bits/stdc++.h>
using namespace std;
int n;
int r[6005];
int e[6005],head[6005],idx=1,ne[6005];
int f[6005][2]; 
int root;
int fa[6005];
int sum[6005]; 
void add(int a,int b)
{
	e[idx]=b;
	ne[idx]=head[a];
	head[a]=idx++;
}
void dfs(int t)
{
	f[t][1]=r[t];
	for(int i=head[t];i;i=ne[i])
	{
		int g=e[i];
		dfs(g);
		f[t][1]+=f[g][0];
		f[t][0]+=max(f[g][1],f[g][0]);
	}
}
int main()
{
	int l,k;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>r[i];
		fa[i]=i;
	}
	for(int i=1;i<=n-1;i++)
	{
		cin>>l>>k;
		add(k,l);
		fa[l]=k;
	}
	for(int i=1;i<=n;i++)
	{
		if(fa[i]==i) 
		{
			root=i;
			break;
		}
	}
	dfs(root);
	int ans=0;
	ans=max(f[root][1],f[root][0]);
	cout<<ans;
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值