1. 程式人生 > >洛谷P1352

洛谷P1352

本題很巧妙。

我們這樣去構想整個樹,對於每個人只有去和不去兩種情況,如果 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;
}