世界真的很大
趁着早上还没开始考试,悄咪咪地做一道树形DP
input里面没读出是多组数据,WA了两发才发现orz
主要是感觉还是不是很熟悉,特别是对于树形这一方面地问题
趁着NOIP之前赶紧地复习一下
就从这道水题开始吧
看题先:
description:
题目给出一棵树,每个节点都有其权值。如果选择了一个节点则不可以选择其父节点,问能取得的最大值
input:
Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0
output:
Output should contain the maximal sum of guests’ ratings.
题目读起来就像是DP,考虑是在树上的问题,所以考虑树形DP
那么考虑树形DP的状态设计,一般与子树有关,即求出子树的答案然后合并上去
考虑在合并的时候,会影响答案合并的状态,就是子树的根节点选或者不选了,选了的话当前节点就不能选,两者的答案不一样当然要分开统计
于是得出状态设计 : f(i,0/1)
表示第i个子树内,i这个点选或者不选的最大值
f(i,0) = sigma max(f(v,0),f(v,1)) + ai,这是由于只要根不选,子树选不选都可以的缘故
f(i,1) = sigma f(v,0) ,这是由于根选了,所有子树的根都不能选的缘故
然后就OK了
完整代码:
#include<stdio.h>
#include<cstring>
#include<algorithm>
using namespace std;
struct edge
{
int v,last;
}ed[100010];
int n,num=0,S;
int a[100010],head[100010],f[100010][2],in[100010];
void init()
{
num=0;
memset(head,0,sizeof(head));
memset(in,0,sizeof(in));
memset(f,0,sizeof(f));
}
void add(int u,int v)
{
num++;
ed[num].v=v;
ed[num].last=head[u];
head[u]=num;
}
void dfs(int u,int fa)
{
f[u][1]=a[u];
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(v==fa) continue ;
dfs(v,u);
f[u][0]+=max(f[v][1],f[v][0]);
f[u][1]+=f[v][0];
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(v,u),add(u,v);
in[u]++;
}
scanf("\n0 0");
for(int i=1;i<=n;i++)
if(!in[i])
{
S=i;
break ;
}
dfs(S,S);
printf("%d\n",max(f[S][1],f[S][0]));
}
return 0;
}
嗯,就是这样