给自己立个flag吧,每天晚上回来想个dp。
题目大意:给你一棵树,树上的父节点和子结点不能同时选,问这棵树可以选的权值最大和。
树形dp,用子节点的值来更新父节点。
有dp[i][0] = sum(max(dp[j][0],dp[j][1])); i->j;
dp[i][1] = sum(dp[j][0]) + d[i]; i->j;
这个因为自己智障还re(!?),忘记清空edgenum这个值了,导致无限加边。晚上脑子也得清醒啊
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 6000+50,inf = 0x3f3f3f3f;
int n;
int d[maxn];
int dp[maxn][2];
struct node
{
int to,next;
node(){}
node(int a,int b){to = a; next = b;}
}edge[maxn<<2];
int deg[maxn],h[maxn];
int edgenum;
void add(int f,int t)
{
edge[edgenum] = node(t,h[f]);
h[f] = edgenum ++;
}
void dfs(int u)
{
int res = 0,res2 = 0;
if(dp[u][0] != -inf) return;
if(h[u] == -1)
{
dp[u][0] = 0;
dp[u][1] = d[u];
return;
}
for(int i = h[u]; ~i ; i = edge[i].next)
{
int v = edge[i].to;
dfs(v);
res += (max(dp[v][1],dp[v][0]));
res2 += dp[v][0];
}
dp[u][0] = res;
dp[u][1] = res2 + d[u];
return;
}
int main()
{
int a,b;
while(~scanf("%d",&n))
{
edgenum = 0;
int flag = 0;
for(int i = 1; i <= n; i++) deg[i] = 0,h[i] = -1,dp[i][0] = dp[i][1] = -inf;
for(int i = 1; i <= n ; i++)
scanf("%d",&d[i]);
while(scanf("%d%d",&a,&b) && a+b)
{
add(b,a);
deg[a] ++;
}
int root = -1;
for(int i = 1; i <= n; i++)
if(deg[i] == 0) {root = i;break;}
dfs(root);
printf("%d\n",max(dp[root][0],dp[root][1]));
}
return 0;
}