题目链接
HDU: http://acm.hdu.edu.cn/showproblem.php?pid=1520
POJ: http://poj.org/problem?id=2342
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0
5
题意:
一个聚会,需要邀请一些人来参加聚会来增加活跃度,但这N个人中,除了一个人以外,其余的人都有直接的上司,如果他们碰到他们的直接的上司的话,那么他们会很不愉快。
现在要求在所有的人都愉快的情况下,使得聚会的活跃度达到最大。
PS:
N个节点形成一棵树,根节点需要用到子节点的数据。
思路:先把每个点的直接的子节点找出来,存在邻接表里。再找出根节点,最后 dfs 从根节点出发找到子节点,然后数据再一层一层的返回。
dp[i][0] :表示 i 这个节点不选, dp[i][1] 代表 i 这个节点选择了。
dp[i][0] += max (dp[子节点][0], dp[子节点][1]);上层节点不选了,那么子节点可选可不选。
dp[i][1] += dp[子节点][0]; 上层节点选了,那么子节点是不可选的。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 6010 int dp[maxn][2]; //dp[i][0]表示:不选 i,dp[i][1]:表示选择 i int vis[maxn]; int a[maxn]; int n; struct node { int to; int next; } e[maxn]; int MAX(int a, int b) { if(a > b) return a; return b; } int cnt, head[maxn]; void addEdge(int u, int v) { e[cnt].to = v; e[cnt].next = head[u]; head[u] = cnt++; } void init() { cnt = 0; memset(head,-1,sizeof(head)); memset(dp,0,sizeof(dp)); memset(vis,0,sizeof(vis)); } void dfs(int node) { dp[node][0] = 0; dp[node][1] = a[node]; for(int i = head[node]; i != -1; i = e[i].next) { int u = e[i].to; dfs(u); dp[node][0] += MAX(dp[u][0], dp[u][1]); dp[node][1] += dp[u][0]; } } int main() { while(~scanf("%d",&n)) { init(); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } int root = 1; int L, K; while(scanf("%d%d",&L,&K)) { if(L==0 && K==0) { break; } vis[L] = 1; addEdge(K, L); } for(int i = 1; i <= n; i++)//寻找根节点 { if(!vis[i]) { root = i; break; } } dfs(root); int ans = MAX(dp[root][0], dp[root][1]); printf("%d\n",ans); } return 0; } /* 7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0 */