dp--树形dp

Problem Description

没有上司的舞会
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

Analysis of ideas

定义dp[n][2]
dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去

那么转移方程就是(假设j是i的儿子)
假设i不去,j去不去都可以
dp[i][0] += max(dp[j][0],dp[j][1])
假设i去,j就不能去
dp[i][1] += dp[j][0]

树形dp的题目一般是先dfs,回溯的时候进行状态转移

Accepted code

#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 10100;
const int M = 1e9+7;
int n,m,k,t;

int dp[maxn][2];        //1去,0不去
int p[maxn];            //代表i去的快乐程度
int pre[maxn];

vector<int> a[maxn];

void dfs(int s)
{   
    dp[s][1] = p[s];
    for(auto i : a[s]) 
    {
        dfs(i);
        dp[s][1] += dp[i][0];
        dp[s][0] += max(dp[i][1],dp[i][0]);
    }
}


int main()
{
    cin(n);
    for(int i = 1; i <= n; i++) 
    {
        cin(p[i]);
    }
    int x,y;
    while(scanf("%d%d",&x,&y) && x)
    {
        a[y].push_back(x);
        pre[x] = y;
    }
    int root;
    for(int i = 1; i <= n; i++) 
    {
        if(pre[i] == 0)
        {
            root = i;
            break;
        }
    }
    dfs(root);
    cout<<max(dp[root][1],dp[root][0])<<endl;
    return 0;
}
posted @ 2020-02-08 08:10  hezongdnf  阅读(129)  评论(0编辑  收藏  举报