动态规划(树形DP)之Anniversary party

来源:互联网 发布:最全英语单词数据库 编辑:程序博客网 时间:2024/05/16 00:59

Anniversary party
Time Limit: 1000MS Memory Limit: 65536KTotal Submissions: 9116 Accepted: 5240

Description

There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests' conviviality ratings.

Input

Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go N – 1 lines that describe a supervisor relation tree. Each line of the tree specification has the form: 
L K 
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line 
0 0 

Output

Output should contain the maximal sum of guests' ratings.

Sample Input

711111111 32 36 47 44 53 50 0

Sample Output

5

  • 题解
很简单的一个树形 dp 的问题,可以很容易的考虑到每个人都有两种选择,也就是来或者不来。那么接下来的部分就容易很多了,我们可以很容易的得到状态表示,dp[i][0]表示第i个人不来;dp[i][1]表示第i个人来。在状态的转移方面,可以得到,如果第i个人不来的话,那么他的所有子节点就都有来或不来两种状态,也就是以i为父节点的都有子节点在来或不来中和的最大值;同时如果第i个人来的话,那么他的所有子节点都只能不来,也就以i为父节点的所有子节点都不能来的和的最大值。在得到了状态转移和表示之后,代码就很容易得到了。我们在写树形 dp 的时候,一般会写成类似于搜索的样子,只不过会在搜索中加入备忘录,这种写法也叫作记忆化搜索。代码中还有关于把无根树转换成有根树的方法,任意选择一个节点作为根节点,从这个根节点开始 DFS,要注意因为在建边的时候都是双向边,所以在DFS的过程中,一定要注意判断当前节点是否是我们设置的父节点,防止循环的递归或者可能产生错误的答案。
#include <bits/stdc++.h>using namespace std;const int maxn=6000+10;int dp[maxn][2],w[maxn];vector<int>g[maxn];int dfs(int x,int s,int fa){    if(dp[x][s]!=-1) return dp[x][s];//记忆化搜索    dp[x][s]=0;    if(s){//去参加        dp[x][s]=w[x];        for(int i=0;i<g[x].size();i++)            if(g[x][i]!=fa)//不为父节点                dp[x][s]+=dfs(g[x][i],0,x);    }    else{        for(int i=0;i<g[x].size();i++)            if(g[x][i]!=fa)                dp[x][s]+=max(dfs(g[x][i],0,x),dfs(g[x][i],1,x));    }    return dp[x][s];}int main(){    int n;    scanf("%d",&n);    memset(dp,-1,sizeof(dp));    for(int i=1;i<=n;i++)        g[i].clear();    for(int i=1;i<=n;i++)        scanf("%d",&w[i]);    int u,v;    while(scanf("%d%d",&u,&v),u||v){        g[u].push_back(v);        g[v].push_back(u);    }    printf("%d\n",max(dfs(1,0,-1),dfs(1,1,-1)));    return 0;}