题目描述
某大学有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; }