HDU1520(樹型dp)

題意:

要開派對,邀請了上司就不能邀請他的下屬,邀請了下屬就不能邀請他的上司,每個人有一個值,求邀請的人的總值最大

思路:

樹形dp:把每個人看成一個點,則該點有兩個狀態:邀請或沒被邀請

定義dp[u][0]爲節點沒被邀請時的值;dp[u][1]爲節點被邀請時的值

狀態轉移方程:

dp[u][0]=sum(max(dp[v][0],dp[v][1])//v爲u的下屬

dp[u][1]+=dp[v][0]//上司邀請了,則下屬只有沒被邀請這種狀態

要求總值,則顯然要求max(f[U][0],f[U][1])//U爲根節點

用dfs遍歷樹用

代碼:

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <map>
#include <vector>
#include <string.h>
using namespace std;
const int N = 6005;
vector <int> G[N];
int value[N];
bool vis[N];
int dp[N][2];
int in[N];
void dfs(int root)
{
    vis[root] = 1;
    dp[root][1] = value[root];
    dp[root][0] = 0;
    for(int i = 0; i < (int)G[root].size(); i++)
    {
        int u = G[root][i];
        if(vis[u]) continue;
        dfs(u);
        dp[root][0]+=max(dp[u][0], dp[u][1]);
        dp[root][1]+=dp[u][0];

    }
    return;
}
int main()
{
    int n;
    while(~scanf("%d", &n) && n)
    {
        memset(vis, 0, sizeof(vis));
        memset(dp, 0, sizeof(dp));
        memset(in, 0, sizeof(in));
        for(int i=0;i<=n;i++)G[i].clear();
        for(int i = 1; i <= n; i++) scanf("%d", &value[i]);
        int v, u;
        while(~scanf("%d%d",&v,&u)&&(v+u))
        {
            G[u].push_back(v);
            in[v]++;
        }
        int root = 1;
        while(in[root]) {root++;}
        dfs(root);
        printf("%d\n",max(dp[root][0], dp[root][1]));
    }
    return 0;
}



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