HDU - 1520 Anniversary party (树形dp)

树形dp模板题~    题目在这里

题目大意:

     Ural大学要举办一个庆典,每个职员都有一个欢乐值,但是没有一个职员想要和他们的直属上司一起出席(会很拘束哎),题目给出职员和他们的上司以及他们的欢乐值,求出这个宴会可能达到的最大的欢乐值是多少。

题目思路:

   很显然职员之间不会有约束关系,那么我们可以发现这些约束关系其实是一棵树,根据题意,我们如果选择这个节点参加,那么他的儿子们就都不能参加,我们只能选择他的孙子;相反,如果这个节点不参加,那么他的儿子可以参加也可以不参加。

   这样我们就可以设出数组dp[i][0]表示不选择i这个节点时可以达到的最大欢乐值,dp[i][1]表示选择这个节点时可以达到的最大欢乐值;那么,dp[root][0]=max(dp[son][0],dp[son][1]),dp[root][1]=dp[son][0];下面结合代码来说明:

另:建树最好用vector邻接表来实现,不但节省空间而且超好用!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 10000

using namespace std;
vector<int>son[maxn];
bool vis[maxn];
int dp[maxn][2];
int n;

void dfs(int root)//分别得到选root和不选root的最大欢乐值
{
    vis[root]=true;
    for(int i=0;i<son[root].size();i++)
    {
        int v=son[root][i];//root的儿子们
        if(!vis[v])
        {
            dfs(v);
            dp[root][1]+=dp[v][0];//注意是要加上的,因为他的子树能达到的其实包含在他能达到的
            dp[root][0]+=max(dp[v][0],dp[v][1]);
        }
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        for(int i=0;i<=n;i++)
            son[i].clear();
        memset(vis,false,sizeof(vis));
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&dp[i][1]);//初始化
            dp[i][0]=0;
        }
        int l,k;
        while(~scanf("%d%d",&l,&k)&&(l+k))//建树过程
        {
            son[l].push_back(k);
            son[k].push_back(l);
        }
        dfs(1);
        int ans=max(dp[1][0],dp[1][1]);
        printf("%d\n",ans);
    }
    return 0;
}

呼呼

猜你喜欢

转载自blog.csdn.net/destiny1507/article/details/81414944
今日推荐