HDU 1520【树形dp入门】

来源:互联网 发布:程序员保护眼睛显示器 编辑:程序博客网 时间:2024/06/05 18:25

题目链接;

题意:
有n个人去参加party,下面n行表示每个人的价值。后边跟许多行a b(0,0结束),表示b是a的父亲节点,且不能使他和他的父亲节点同时参加,求可以获得最大的财富值。
思路:
树形dp的入门,注意遍历树的回溯操作。

#include <cstdio>#include <algorithm>#include <cstring>#include <cmath>using namespace std;#define MAXN 10010int a[MAXN], out[MAXN], head[MAXN << 2];int dp[MAXN][2], vis[MAXN];int cnt = 0;// dp[i][flag]: 表示编号为i的节点,其子节点能获得的最大财富值(flag的真假表示其本人是否出席);struct node {    int to;    int next;}edge[MAXN << 2];void init() {    cnt = 0;    memset(dp, 0, sizeof(dp));    memset(vis, 0, sizeof(vis));    memset(out, 0, sizeof(out));    memset(head, -1, sizeof(head));}void add_edge(int u, int v) {    edge[cnt].to = v;    edge[cnt].next = head[u];    head[u] = cnt++;}void dfs(int x) {    vis[x] = 1;    dp[x][1] = a[x]; //初始化出席获得的财富值;     for(int i = head[x]; i != -1; i = edge[i].next) {        int u = edge[i].to;        if(!vis[u]) {            dfs(u);            dp[x][0] += max(dp[u][1], dp[u][0]); //没出席,加上子节点的最大财富值;             dp[x][1] += dp[u][0]; //出席了,子节点就只能不出席;         }    }}int main() {    int n, u, v;    while(scanf("%d", &n) != EOF) {        init();        for(int i = 1; i <= n; i++) {            scanf("%d", &a[i]);        }        while(scanf("%d %d", &v, &u) && (u + v)) {            add_edge(u, v);            out[v]++;        }        int id;        for(int i = 1; i <= n; i++) {            if(!out[i]) {  //只有一棵树,找根节点;                 id = i;                break;            }        }        dfs(id); //遍历树;         printf("%d\n", max(dp[id][0], dp[id][1]));    }    return 0;} 
原创粉丝点击