2019暑假集训 周年纪念晚会


题目描述
Ural 州立大学的校长正在筹备学校的80周年纪念聚会。由于学校的职员有不同的职务级别,可以构成一棵以校长为根的人事关系树。每个资源都有一个唯一的整数编号,从1到N编号,且对应一个参加聚会所获得的欢乐度。为使每个职员都感到快乐,校长设法使每个职员和其直接上司不会同时参加聚会。

你的任务是设计一份参加聚会者的名单,使总欢乐度最高。
输入
第一行是一个整数N;

接下来N行对应N个职员的欢乐度,第i行的一个整数为第i个职员的欢乐度pi;

接着是学校的人事关系树,每一行格式为 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


由于关系网络呈一棵树 很容易想到树形dp
所以对于每个人我们有去(1)不去(0)两种可能:
(1)第x个人去,则其儿子不可能去,即dp[x][1]+=dp[y][0];
(2)第x个人不去,则其儿子可能去可能不去,两种可能取最小值,则dp[x][0]+=min(dp[y][0],dp[y][1]);
所以上代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,p[10050],dp[10050][2],head[10050],num,book[10050],root=1;
struct edge
{
    int u,v,nxt;
}e[200500];
void add(int u,int v)
{
    e[++num].u=u;e[num].v=v;
    e[num].nxt=head[u],head[u]=num;
}
void DP(int x,int fa)
{
    for(int st=head[x];st!=-1;st=e[st].nxt)
    {
        int y=e[st].v;
        if(y==fa)continue;
        DP(y,x);
//      dp[x][0]=max(dp[x][0],dp[y][1]);
//      dp[x][1]=max(dp[x][1],dp[y][0]+p[x]);
        dp[x][0]+=max(dp[y][1],dp[y][0]);
        dp[x][1]+=dp[y][0];
    }
    dp[x][1]+=p[x];
    return;
}
int main()
{
    memset(head,-1,sizeof head);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&p[i]);
    int l=1,k=1;
    while(!(l==0&&k==0))scanf("%d%d",&l,&k),add(k,l),book[l]=1;
    while(book[root])root++;
    DP(root,-1);
//  putchar('\n');
//  putchar('\n');
//  for(int i=1;i<=n;i++)printf("%d %d\n",dp[i][0],dp[i][1]);
    int ans=max(dp[root][0],dp[root][1]);
    printf("%d",ans);
    return 0;
}

 

posted @ 2019-08-13 10:32  lqxssf  阅读(201)  评论(0编辑  收藏  举报