ural(Timus) 1039. Anniversary Party

树DP

经典问题,公司聚会,下属和直属上司不能共存,给出每个人的快乐值,再给出每个人的编号和他的上司,选出一些人参加聚会使快乐值最大

/*

从叶子开始选择,每个节点只有选不和不选两种可能,dp[rt][0],dp[rt][1]

分别表示选和不选该节点

dp[rt][1]=sum{ dp[son][0] }+val[rt] , 因为跟选了它的儿子就全部不能选

dp[rt][0]=sum{ max{dp[son][0] , dp[son][1]} }

如果根不选,那么儿子的选择就多样化了,每个儿子又是互不干扰的

所以令每个儿子最优,加起来根就是最优的,而每个孩子无非还是选和不选,一比较就能

得到每个儿子的最优方案

而对于叶子,dp[rt][0]=0;dp[rt][1]=val[rt];

*/



#include <cstdio>

#include <cstring>

#include <vector>

using namespace std;

#define N 6010



vector<int>a[N];

int dp[N][2];

int val[N];

int n,root;

bool mark[N],vis[N];



int max(int p ,int q)

{

    return p>q?p:q;

}



void dfs(int rt)

{

    vis[rt]=true;

    int size=a[rt].size();

    dp[rt][0]=0; dp[rt][1]=val[rt];

    for(int i=0; i<size; i++) 

    {

        int son=a[rt][i];

        if(!vis[son])

        {

            dfs(son);

            dp[rt][1] += dp[son][0];

            dp[rt][0] += max(dp[son][0] , dp[son][1]);

        }

    }

}



void solve()

{

    for(int i=1; i<=n; i++)

        if(!mark[i])

        { root=i; break; }

    a[0].push_back(root);

    a[root].push_back(0);

    root=0; val[root]=0;

    memset(vis,false,sizeof(vis));

    dfs(root);

    printf("%d\n",max(dp[root][0] , dp[root][1]));

}



int main()

{

    while(scanf("%d",&n)!=EOF)

    {

        memset(mark,false,sizeof(mark));

        for(int i=1; i<=n; i++) a[i].clear();

        for(int i=1; i<=n; i++) scanf("%d",&val[i]);

        while(1)

        {

            int u,v;

            scanf("%d%d",&u,&v);

            if(!u && !v) break;

            mark[u]=true; 

            a[u].push_back(v);

            a[v].push_back(u);

        }

        solve();

    }

    return 0;

}

 

你可能感兴趣的:(part)