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;
}

 

posted @ 2013-04-09 23:09  Titanium  阅读(359)  评论(0编辑  收藏  举报