一道很简单的树形dp,之前也是没有做过,从简单的开始做起。
题意:就是说公司要开个party,每个人都有一个欢乐值,条件是一个人如果到场那么它的直系上司不能在,问最大的欢乐值。
思路:建棵树,也可能是很多棵树,然后dp[i][1]表示第i个人的上司在,0代表上司不在。那么转移方程是
dp[i][0]=max(求和(dp[child][1])+w[i],求和(dp[child][0]))
dp[i][1]=求和(dp[child][0]);
边界处理,就是叶子节点。dp[i][0]=w[i],dp[i][1]=0;
然后一个dfs过一遍就好了。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=6005;
int dp[maxn][2];
int rat[maxn];
int in[maxn];
int out[maxn];
int n;
struct node{
int v,next;
};
int cnt;
int head[maxn];
node edge[maxn<<1];
void add(int a,int b){
edge[cnt].v=b;
edge[cnt].next=head[a];
head[a]=cnt++;
}
int dfs(int u,int f){
int ans1=0,ans2=0;
for(int i=head[u];i!=-1;i=edge[i].next){
int v;
v=edge[i].v;
if(v==f) continue;
dfs(v,u);
ans1+=dp[v][1];
ans2+=dp[v][0];
}
dp[u][0]=max(ans1+rat[u],ans2);
dp[u][1]=ans2;
return max(dp[u][0],dp[u][1]);
}
int main(){
while(~scanf("%d",&n)){
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
memset(rat,0,sizeof(rat));
memset(dp,0,sizeof(dp));
cnt=0;
for(int i=1;i<=n;i++){
scanf("%d",&rat[i]);
}
int x,y;
while(scanf("%d%d",&x,&y)){
if(x==0&&y==0) break;
add(y,x);
add(x,y);
in[x]++;
out[y]++;
}
for(int i=1;i<=n;i++){
if(out[i]==0){
dp[i][0]=rat[i];
}
}
int i,ans=0;
for(i=1;i<=n;i++){
if(in[i]==0){
ans+=dfs(i,0);
}
}
printf("%d\n",ans);
}
return 0;
}