【poj2342】Anniversary party【树形DP】

本文解析了POJ英文原题“周年聚会”的算法思路,通过动态规划(DP)求解最大活跃度问题,详细介绍了边递归边DP的过程及代码实现。

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

题目大意

poj英文原题&样例(周年聚会)
网页翻译器

大家自己看。

分析

这个题真的跟没有上司的晚会一模一样!!只是改了一下题目描述。同样是找到根节点之后开始边递归边DP。
由题意得,父节点(上司)选了,那么所有儿子(下属)都不能选;父节点不选,那么所有儿子可选可不选。我们设 f [ i ] [ 1 ] f[i][1] f[i][1]为选了 i i i中这个点的最大活跃度, f [ i ] [ 0 ] f[i][0] f[i][0]为不选这个点的最大活跃度。所以动态转移方程: f [ i ] [ 1 ] = f [ i ] [ 1 ] + f [ a [ i ] . y ] [ 0 ] f[i][1]=f[i][1]+f[a[i].y][0] f[i][1]=f[i][1]+f[a[i].y][0] f [ i ] [ 0 ] = m a x ( f [ a [ i ] . y ] [ 0 ] , f [ a [ i ] . y ] [ 1 ] ) + f [ i ] [ 0 ] f[i][0]=max(f[a[i].y][0],f[a[i].y][1])+f[i][0] f[i][0]=max(f[a[i].y][0],f[a[i].y][1])+f[i][0]

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,a[10001],h[10001],f[10001][2],v[10001],tot,m;
struct node
{
	int x,y,next;
}e[10001];
void add(int x,int y)
{
	//e[++tot]=(node){x,y,h[x]};//邻接表一句顶四句 
	tot++;
	e[tot].x=x;
	e[tot].y=y;
	e[tot].next=h[x];
	h[x]=tot;
} 
void dp(int k)
{
	f[k][1]=a[k];
	for(int i=h[k];i>0;i=e[i].next)
	{
		dp(e[i].y);
		f[k][1]=f[k][1]+f[e[i].y][0];//如果他选,儿子就不选 
		f[k][0]=max(f[e[i].y][0],f[e[i].y][1])+f[k][0];//他不选,儿子可选可不选 
	}
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
    	cin>>a[i];
    }
    int x,y;
    for(int i=1;i<=n;i++)
    {
    	cin>>x>>y;
    	if(x==0&&y==0) continue;
    	add(y,x);
    	v[x]=1;//证明他不是根节点,x是y的儿子 
    }
    for(int i=1;i<=n;i++)
    {
    	if(v[i]==0)
    	{
            m=i;//找根节点
			break;		
    	}
    }
    dp(m);//从根节点开始DP 
    cout<<max(f[m][1],f[m][0]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值