题目描述
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入输出格式
输入格式:第一行一个整数N。(1<=N<=6000)
接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
最后一行输入0 0
输出格式:输出最大的快乐指数。
树形DP经典题。
首先显而易见,可以设dp[i]表示以i为根的子树上最大的欢乐值,但由于每个人是否参加舞会会对他的下属能否参加舞会有影响,也就是说有后效性,所以仅仅这样设计是不够的。
考虑加第二维数组,dp[i][j]表示i去和不去时以i为根的子树上最大欢乐值,其中j=0表示i不去,j=1表示去。
那么状态转移方程就比较容易了:
上司不来,下属就能来,上司来,下属不来,所以只需要对代表上司来不来的flag取反就是下属状态
for(int i=head[now];i;i=e[i].next) dp[now][flag]+=dfs(e[i].to,!flag);
剩下的工作就很简单了,只需要注意有可能有负的快乐值,所以初始化的时候要注意
dp[i][1]=max(0,ha[i])
代码:
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; struct edge { int next; int to; }e[10000]; int dp[10000][2]; int ha[10000]; int in[10000]; int head[10000]; int cnt; void insert(int u,int v) { e[++cnt].next=head[u]; head[u]=cnt; e[cnt].to=v; in[v]++; } int dfs(int now,bool flag) { if(!head[now]){ if(flag) return ha[now]; else return 0; } for(int i=head[now];i;i=e[i].next) dp[now][flag]+=dfs(e[i].to,!flag); return dp[now][flag]; } int main() { int n,x,y,root; cin>>n; for(int i=1;i<=n;i++) scanf("%d",&ha[i]); for(int i=1;i<=n;i++) dp[i][1]=max(ha[i],0); for(int i=1;i<n;i++){ scanf("%d%d",&x,&y); insert(y,x); } scanf("%d%d",&x,&y); for(int i=1;i<=n;i++){ if(!in[i]){ root=i; break; } } dfs(root,0); dfs(root,1); cout<<max(dp[root][0],dp[root][1]); return 0; }