【CODEVS1380】【luogu1352】没有上司的舞会

题目描述

某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。


输入

第一行一个整数N。(1<=N<=6000)

接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)

接下来N-1行,每行输入一对整数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的入门题。dp[ i ][ 0 ] 表示不选 i 结点的最大快乐指数,dp[ i ][ 1 ] 表示选择 i 结点的最大快乐指数。

那么容易得到: dp[ i ][ 0 ] +=  max( dp[ son[ i ] ][ 1 ] , dp[ son[ i ][ 0 ] )      ,      dp[ i ][ 1 ] += dp[ son[ i ] ][ 0 ]

然后dfs就ok啦。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long

const int maxn=6000+50;

int dp[maxn][2],n,happy[maxn],x,y,root;
int fir[maxn],nex[maxn],to[maxn],ecnt;
bool p[maxn];

template<typename T>void read(T& aa){
    char cc; ll ff;aa=0;cc=getchar();ff=1;
    while((cc<'0'||cc>'9')&&cc!='-') cc=getchar();
    if(cc=='-') ff=-1,cc=getchar();
    while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar();
    aa*=ff;
}

void add_edge(int u,int v){
    nex[++ecnt]=fir[u];fir[u]=ecnt;to[ecnt]=v;
}

void dp1(int x){
    dp[x][0]=0;
    dp[x][1]=happy[x];
    for(int i=fir[x];i;i=nex[i]){
        int v=to[i];
        dp1(v);
        dp[x][0]+=max(dp[v][0],dp[v][1]);
        dp[x][1]+=dp[v][0];
    }
}

int main(){
    memset(p,true,sizeof(p));
    read(n);
    for(int i=1;i<=n;i++) read(happy[i]);
    for(int i=1;i<n;i++){
        read(x),read(y);
        add_edge(y,x);
        p[x]=false;
    }
    read(x),read(y);
    for(int i=1;i<=n;i++) if(p[i]) root=i;
    dp1(root);
    cout<<max(dp[root][1],dp[root][0])<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/rlddd/p/9491575.html