POJ 2342 Anniversary party【树形DP】

树形dp入门题,给n个人参加聚会,每个人有个活跃度,他们之间有上司和下属关系,如果上司参加了则下属不去参加,求最大活跃度(上司和下属关系都是直接关系,不需要考虑间接的情况)。

定义

dp[rt][0]:以rt为根的树,rt本身不来的最大活跃度
dp[rt][1]:以rt为根的树,rt本身来的最大活跃度

dp[rt][1] = dp[rt][1] + dp[sonI][0];      //上司来,则下属不能来 
dp[rt][0] = dp[rt][0] + max(dp[sonI][0],dp[sonI][1]);  //上司不来,下属可来可不来

代码就好写了,不过需要先找到根节点,再往下递归求方程,最后输出max( dp[root][0], dp[root][1] )即可。

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long
#define clr( a , x ) memset ( a , x , sizeof (a) );
#define RE freopen("1.in","r",stdin);
#define WE freopen("1.out","w",stdout);
#define SpeedUp std::cout.sync_with_stdio(false);

const int maxn = 6005;
const int inf = 0x3f3f3f3f;
int father[maxn];
int dp[maxn][2];
int vis[maxn];
int n;

void tree(int rt){
    vis[rt] = 1;
    for (int i = 1; i <= n; ++i){
        if(!vis[i] && father[i] == rt){    //下属
            tree(i);
            dp[rt][1] += dp[i][0];              //上司来,则下属不能来
            dp[rt][0] += max(dp[i][0],dp[i][1]);    //上司不来,下属可来可不来
        }
    }
}

int main(){
    int p,q;

    while(cin>>n){
        clr(vis,0);
        clr(dp,0);
        clr(father,0);
        for (int i = 1; i <= n; ++i){
            cin>>dp[i][1];
        }
        while(cin>>p>>q,p||q){
            father[p] = q;
        }

        int rt = 1;         //1号人肯定在
        while(father[rt]){  //从任意一点开始找根节点
            rt = father[rt];
        }
        tree(rt);
        cout<<max(dp[rt][0],dp[rt][1])<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u012469987/article/details/51278529