题意:学校要开一个聚会。学校的教职工之间有上下级关系,为了让所有人开心,宴会组织者决定不会同时邀请一个人和他的上级对于每一个人,他能给聚会带来的欢乐度有一个值,问组织者该邀请哪些人能够使宴会的欢乐度达到最大值。
和https://blog.csdn.net/lanshan1111/article/details/81989680和这道题一样
#include<stdio.h>
#include<string.h>
#define N 6005
struct node
{
int pa,son;
int next;
}point[N];
//其实从这个结构体就可以看出很多东西,这就是一个静态链表,在计算过程中遍历一个节点的所有子节点的操作也是和链表完全相同的。
//不过我这都是后知后觉啊。
int dp[N][2],list[N],flag[N],value[N];
int pos;
int Max(int x,int y)
{
return x>y?x:y;
}
void add(int pa,int son)
{
point[pos].next=list[pa]; //以静态链表的形式存储一个父节点下面所有的子节点。
point[pos].pa=pa;
point[pos].son=son;
list[pa]=pos++;//pos从0开始
/*
邻接表模板:
point[pos].next=list[pa];
point[pa].pa=pa;
point[to].son=son;
list[pa]=pos++;
*/
return ;
}
void dfs(int root) //这道题说起来是树形DP,但是最没有讲的价值的就是这个DP。就是个入门级数塔的操作放在树上了。
{
if(list[root]==-1)
{
dp[root][1]=value[root];
dp[root][0]=0;
return ;
}
int now=list[root];
dp[root][0]=0;
dp[root][1]=value[root];
while(now!=-1)
{//也可以写成for(now=list[root];now!=-1;now=point[now].next),那下面也要作出改变;
dfs(point[now].son);
dp[root][1]+=dp[point[now].son][0]; //既然取了父节点的值,子节点的值就不能再取了。
//父节点的值没有取,子节点的值分取和不取两种情况,取其中较大的那种情况。
dp[root][0]+=Max(dp[point[now].son][1],dp[point[now].son][0]);
now=point[now].next;//这个子节点计算过了,就要开始计算下一个子节点了。
}
return ;
}
int main()
{
int i,n;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d",&value[i]);//记录每一个点的值
int a,b;
pos=0;
memset(list,-1,sizeof(list));
memset(flag,0,sizeof(flag));
while(scanf("%d%d",&a,&b),a+b)
{
add(b,a); //将边加入树中b是a的父节点;
flag[a]=1; //记录a有父节点,不可能是祖节点。
}
a=1;
while(flag[a]==1)
a++; //从a往后查,遇到的第一个flag[a]的值是-1的点,这就是大名鼎鼎的祖节点了。
dfs(a);//先找出父节点;进行深搜;
printf("%d\n",Max(dp[a][0],dp[a][1]));
}
return 0;
}