洛谷P1352

版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}

猜你喜欢

转载自blog.csdn.net/qq_40924940/article/details/84981125