题目链接:没有上司的聚会
第一个树形dp的题,不想建树,想了一个中午终于靠数组解决了。
具体方法就是定义dp[n][2],dp[i][1]表示选第i个人能得到的最大价值,dp[i][0]表示不选第i个人能得到的最大价值,则状态转移方程:
dp[i][0] = max(dp[son][0],dp[son][1]);
dp[i][1] = dp[son][0] + val[i];
由于不想建树,就模仿孩子兄弟表示法又开了两个数组child[n],bro[n],其中child[i]表示i的第一个孩子,bro[i]表示i的兄弟;
AC代码:
#include <stdio.h>
#include <string.h>
#define max(a,b) ((a) > (b) ? (a) : (b))
#define MAXN 100010
typedef struct NODE{
int dp[2];
int flag; //标记是否有父节点
}CNODE;
CNODE people[MAXN]; //人员
int child[MAXN]; //child[i]表示i的第一个孩子
int bro[MAXN]; //bro[i]表示i的兄弟
int n;
void Init(){ //初始化与输入函数
int i;
int k,l;
memset(people,0,sizeof(people));
memset(child,0,sizeof(child));
memset(bro,0,sizeof(bro));
for(i = 1;i <= n;i ++){
scanf("%d",&people[i].dp[1]);
}
//处理父子兄弟关系
for(i = 1;i < n;i ++){
scanf("%d%d",&k,&l);
people[k].flag = 1;
if(child[l] == 0){
child[l] = k;
} else {
l = child[l];
while(bro[l] != 0){
l = bro[l];
}
bro[l] = k;
}
}
}
void DFS(int v){
int i = child[v];
if(i != 0){
do{
DFS(i);
people[v].dp[1] += people[i].dp[0];
people[v].dp[0] += max(people[i].dp[1],people[i].dp[0]);
i = bro[i];
}while(i);
/* for(i = child[v];bro[i];i = bro[i]){
DFS(i);
people[v].dp[1] += people[i].dp[0];
people[v].dp[0] += max(people[i].dp[1],people[i].dp[0]);
}
*/
}
}
int main(){
int i;
while(scanf("%d",&n) != EOF){
Init();
for(i = 1;i <= n;i ++){
if(!people[i].flag){ //如果people[i].flag == 0则表示i是根
DFS(i);
break;
}
}
printf("%d\n",max(people[i].dp[0],people[i].dp[1]));
}
return 0;
}