您的位置:首页 > 其它

HDU 1520【树形dp入门】

2017-10-18 00:09 435 查看
题目链接;

题意:

有n个人去参加party,下面n行表示每个人的价值。后边跟许多行a b(0,0结束),表示b是a的父亲节点,且不能使他和他的父亲节点同时参加,求可以获得最大的财富值。

思路:

树形dp的入门,注意遍历树的回溯操作。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define MAXN 10010
int 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: