DP - 樹形DP - 沒有上司的舞會

DP - 樹形DP - 沒有上司的舞會

題意:

Ural大學有N名職員,編號爲1~N。

他們的關係就像一棵以校長爲根的樹,父節點就是子節點的直接上司。

每個職員有一個快樂指數,用整數 Hi 給出,其中 1≤i≤N。

現在要召開一場週年慶宴會,不過,沒有職員願意和直接上司一起參會。

在滿足這個條件的前提下,主辦方希望邀請一部分職員參會,使得所有參會職員的快樂指數總和最大,求這個最大值。

輸入格式

第一行一個整數N。

接下來N行,第 i 行表示 i 號職員的快樂指數Hi。

接下來N-1行,每行輸入一對整數L, K,表示K是L的直接上司。

輸出格式

輸出最大的快樂指數。

數據範圍

1≤N≤6000,
−128≤Hi≤127

輸入樣例:

7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5

輸出樣例:

5

分析:

對於一棵樹而言,各子樹分支的的計算是相互獨立的。
u我們考慮每個節點u選或不選。

f[u][0]u狀態表示,f[u][0]:表示不選節點u的最大收益。
f[u][1]u\qquad\qquad\quad f[u][1]:表示選節點u的最大收益。

uj狀態計算:設節點u的孩子節點爲j
uf[u][0]+=max(f[j][0],f[j][1])①、不選節點u:f[u][0]+=max(f[j][0],f[j][1])
uf[u][1]+=f[j][0]②、選節點u:f[u][1]+=f[j][0]

具體落實:

boolroot①、用鄰接表來存圖,同時需要用一個bool數組來標記根節點root。

②、從根節點開始遞歸計算各節點的左右子樹的權值之和的最大值。

max(f[root][0],f[root][1])③、最終答案就是取max(f[root][0],f[root][1])。

代碼:

#include<iostream>
#include<algorithm>
#include<cstring>

using namespace std;

const int N=6010;

int n,w[N],h[N],f[N][ 2];
int e[N],ne[N],idx;
bool has_fa[N];

void add(int a,int b)
{
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u)
{
    f[u][1]=w[u];
    
    for(int i=h[u];~i;i=ne[i])
    {
        int j=e[i];
        dfs(j);
        
        f[u][1]+=f[j][0];
        f[u][0]+=max(f[j][0],f[j][1]);
    }
}

int main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    
    memset(h,-1,sizeof h);
    for(int i=1;i<n;i++)
    {
        int a,b;
        cin>>a>>b;
        add(b,a);
        has_fa[a]=true;
    }
    
    int root=1;
    while(has_fa[root]) root++;
    
    dfs(root);
    
    printf("%d\n",max(f[root][0],f[root][1]));
    
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章