hdu1250Anniversary party 树形dp入门基础

http://acm.hdu.edu.cn/showproblem.php?pid=1520

我们通过这个题来简单学习一下树形dp。
题目大意:
n个人形成一个关系树,每个节点代表一个人,节点的根表示这个人的唯一的直接上司,只有根没有上司。要求选取一部分人出来,使得每2个人之间不能有直接的上下级的关系,求选出的中最多的rating。
用dp[i][0]表示不选择i点时,i点及其子树能选出的最多的rating,dp[i][1]表示选择i点时,i点及其子树的最多的rating;

状态转移方程:
对于叶子节点 dp[k][0] = 0, dp[k][1] = rating[k];
对于非叶子节点i,
dp[i][0] = ∑max(dp[j][0], dp[j][1]) (j是i的儿子)
dp[i][1] = rating[i] + ∑dp[j][0] (j是i的儿子)
最多人数即为max(dp[root][0], dp[root][1])

#include <cstdio>
#include <cstring>
#include <cctype>
#include <cmath>
#include <set>
#include <map>
#include <list>
#include <queue>
#include <deque>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=6050;

int n;
long long  dp[N][2];
int rating[N];
int f[N];
vector<int>v[N];
void slove(int root)
{
    long long  dp0=0,dp1=0; 
    if(v[root].size()==0)
    {
        dp[root][0]=0;//not put on root
        dp[root][1]=rating[root];//put on root
        return;
    }
    for(int i=0;i<v[root].size();i++)
    {
        slove(v[root][i]);
        dp1+=dp[v[root][i]][0];
        dp0+=max(dp[v[root][i]][0],dp[v[root][i]][1]);
    }
    dp[root][0]=dp0;
    dp[root][1]=dp1+rating[root];
}
int main()
{
#ifdef LOCAL
    freopen("date.in","r",stdin);
    freopen("date.out","w",stdout);
#endif
    int root,x,y;
    while(scanf("%d",&n)==1)
    {

        for(int i=1;i<=n;i++)
            scanf("%d",&rating[i]);
        for(int i=1;i<=n;i++)
        {
            f[i]=-1;
            v[i].clear();
        }
        while(scanf("%d%d",&x,&y))
        {
            if(x==0&&y==0)
                break;
            v[y].push_back(x);
            f[x]=y;
        }
        root=1;
        while(f[root]!=-1) root=f[root];
        slove(root);
        printf("%lld\n",max(dp[root][0],dp[root][1]));
    }
    return 0;
}

你可能感兴趣的:(dp)