HDU1520
Posted i am back
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU1520相关的知识,希望对你有一定的参考价值。
该题目的意思是,给定一棵树,每个点有个权值,目标是选择某些点使总权值和最大,但是要求任意一对父节点和子节点不能一起选择。
思路:DP。说的高大尚一点就是树形DP。
从子节点往根节点走,DP[ i ][ 0 ]表示以i为顶点的子树,不选 i 点的情况下最大值。
DP[ i ][ 1 ]表示以 i 为顶点的子树,选 i 点的情况下最大值。
由此就可以想到如下转移方程:
dp[ i ][ 0 ] = sum{ max { dp[ j ][ 0 ], f[ j ][ 1 ] }, j 是 i 的儿子节点}
该条的意思就是,当不选i点时,它的儿子节点可以不选也可以选,所以对每个子节点选或不选的情况取个最大的和。
dp[ i ][ 1 ] = val[ i ] + sum{ dp[ j ][ 0 ], j 是 i 的儿子节点}
这条的意思是当选了 i 点时,它的儿子节点必须是不能选,所以直接取所有子节点不选的和。
DFS的作用是实现从底向上,虽然表面写法是从顶向下,但是回溯回来之后便是从底向上。
tree数组的作用是找寻根节点(其实也是由输入来决定的根节点),或者说是选择一个点作为根节点更准确。
#include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<queue> #include<cmath> #include<cstring> using namespace std; #define INF 0x3f3f3f3f; vector<int>q[10000]; int tree[10000]; int val[10000]; int dp[10000][2]; int vis[10000]; int n,m; void dfs(int u){ vis[u] = true; dp[u][0] = 0; dp[u][1] = val[u]; for(int i=0; i<q[u].size(); ++i){ int v = q[u][i]; if(vis[v]) continue; dfs(v); dp[u][0] += max(dp[v][1], dp[v][0]); dp[u][1] += dp[v][0]; } } int main(){ while(~scanf("%d", &n) && n) { for(int i=1; i<=n; ++i) q[i].clear(); for(int i=1; i<=n; ++i) scanf("%d", &val[i]); memset(tree, 0, sizeof(tree)); int u, v; while(~scanf("%d%d", &v, &u) && v+u) { q[u].push_back(v); ++tree[v]; } memset(dp, 0, sizeof(dp)); for(int i=1; i<=n; ++i)if(!tree[i]) { memset(vis, 0, sizeof(vis)); dfs(i); printf("%d\n", max(dp[i][0], dp[i][1])); break; } } return 0; }
以上是关于HDU1520的主要内容,如果未能解决你的问题,请参考以下文章
HDU1520 Anniversary party(树形dp入门题)