简单树形动态规划(ural 1039 没有上司的晚会)

本文介绍了一个关于晚会邀请的问题,目标是在避免邀请上下级共存的情况下,最大化晚会的氛围值总和。通过使用图论和动态规划的方法,文章提供了一种有效的解决方案。

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

没有上司的晚会(party)Ural 1039
http://acm.timus.ru/problem.aspx?space=1&num=1039
【问题描述】
有个公司要举行一场晚会。为了能玩得开心,公司领导决定:如果邀请了某个人,那么一定不会邀请他的上司(上司的上司,上司的上司的上司……都可以邀请)。每个参加晚会的人都能为晚会增添一些气氛,求一个邀请方案,使气氛值的和最大。所有员工的编号为1~N。

【输入格式】
第1行一个整数N(1<=N<=6000)表示公司的人数。
接下来N行每行一个整数。第i行的数表示第i个人的气氛值x(-128<=x<=127)。
接下来每行两个整数L,K。表示K是 L的上司。
输入以0 0结束。
【输出格式】
一个数,最大的气氛值和。
【样例输入】
输入:
7
1 1 1 1 1 1 1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
输出:
5

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
struct node
{
    int x,y,next;
}a[110000];int len,last[110000];
void ins(int x,int y)
{
    len++;
    a[len].x=x;a[len].y=y;
    a[len].next=last[x];last[x]=len;
}
int fa[11000],son[11000];
int f[11000][2];
//f[i][j]:1表示这个人来,0表示不来
int v[110000];
void treedp(int x)
{
    f[x][1]=v[x];
    for(int k=last[x];k;k=a[k].next)
    {
        treedp(a[k].y);
    }

    //讨论f[x][1]的情况
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        f[x][1]+=f[y][0];
        //如果他来的话,那么他的儿子(下属)就不能来;
    }

    //讨论f[x][0]的情况
    f[x][0]=0;
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        f[x][0]+=max(f[y][1],f[y][0]);
        //如果他不来,那么他的儿子来不来都可以
    }
}
int main()
{
    freopen("party.in","r",stdin);
    freopen("party.out","w",stdout);
    int n;
    scanf("%d",&n);
    memset(f,-1,sizeof(f));
    memset(fa,0,sizeof(fa));
    for(int i=1;i<=n;i++)scanf("%d",&v[i]);
    int xx,yy;len=0;
    memset(last,0,sizeof(last));
    while(scanf("%d%d",&xx,&yy)!=EOF)
    {
        if(xx==0 && yy==0)break;
        ins(yy,xx);fa[xx]=yy;son[yy]=xx;
    }
    int root;//根节点(Boss)
    for(int i=1;i<=n;i++)
        if(fa[i]==0){root=i;break;}
    for(int i=1;i<=n;i++)
    {
        if(son[i]==0)
        {
            f[i][0]=0;
        }
    }
    treedp(root);
    printf("%d\n",max(f[root][1],f[root][0]));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值