版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40924940/article/details/84981125
本题很巧妙。
我们这样去构想整个树,对于每个人只有去和不去两种情况,如果 A 去了,A的手下必定不去,反之如果A不去,那么A的手下可以去,也可以不去,既然只有两种情况我们就可以构造一个状态转移方程:设置两个Dp 一个记录当前节点不去时的总快乐度,一个记录去的话的总快乐度
Dp1[x](假设A去舞会)+= Dp2[x.to] ;
Dp2[x](假设A没去) += max( Dp1[x.to], Dp2[x.to] )
那么整个转移方程出来了,我们就可以开始构造整个树了
把子节点设为下属,父节点设为上司,然后还是后序遍历的思路,找出一个最大值。
以下就是 AC 代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1e5+5;
int head[maxn],tot;
int num[maxn];
struct node
{
int nxt,to;
}ed[maxn];
int vis[maxn];
int dp[maxn][2];
void add(int u,int v)
{
ed[++tot].to = v;
ed[tot].nxt = head[u];
head[u] = tot;
}
void dfs(int s)
{
dp[s][0] = 0;
dp[s][1] = num[s];
for(int i=head[s];~i;i=ed[i].nxt)
{
int to = ed[i].to;
dfs(to);
dp[s][0] += max(dp[to][0],dp[to][1]);
dp[s][1] += dp[to][0];
}
return ;
}
int main()
{
int n;
scanf("%d",&n);
tot = 1;
memset(vis,0,sizeof vis);
memset(head,-1,sizeof head);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
for(int i=1;i<=n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(y,x); //注意这里建链接的方式,父节点设为上司
vis[x] = 1;
}
int rt;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
rt = i;
break;
}
}
dfs(rt);
printf("%d\n",max(dp[rt][0],dp[rt][1]));
return 0;
}