题目描述 Description Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。 输入描述 Input Description 第一行一个整数N。(1<=N<=6000) 接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127) 接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。 最后一行输入0,0。 输出描述 Output Description 输出最大的快乐指数。 样例输入 Sample Input 7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0 样例输出 Sample Output 5 数据范围及提示 Data Size & Hint 各个测试点1s
芒果君:这道树形DP首先在建图上有一点难度,其实很像邻接表。不过在我写完上句话构思的时候突然看到一个更简单的方法,就是用vector储存子节点再进行递归。找到没有父亲的节点当作祖宗进行DFS(DP),DP决策的部分主要抓住状态——这个人参不参加舞会(是非用1、0表示),f[x]数组表示以x为根节点的最优解。如果参加,就继承他子节点不参加的情况,f[x][1]+=f[son][0];不参加则相反,但要注意,由于每个点的权值有正有负,他的子节点可参加可不参加,即f[x][0]+=max(f[son][0],f[son][1])。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define l 6010 5 using namespace std; 6 struct Node{ 7 int fa,so,ne; 8 }p[l]; 9 int n,cnt,exfa[l],w[l],f[l][2],hl[l]; 10 void add(int x,int y) 11 { 12 p[++cnt].fa=x; 13 p[cnt].so=y; 14 p[cnt].ne=hl[x]; 15 hl[x]=cnt; 16 } 17 int find() 18 { 19 for(int i=1;i<=n;++i) if(!exfa[i]) return i; 20 } 21 void dfs(int x) 22 { 23 f[x][1]=w[x]; 24 f[x][0]=0; 25 if(!hl[x]) return; 26 for(int i=hl[x];i;i=p[i].ne){ 27 dfs(p[i].so); 28 f[x][1]+=f[p[i].so][0]; 29 f[x][0]+=max(f[p[i].so][1],f[p[i].so][0]); 30 } 31 } 32 int main() 33 { 34 int x,y; 35 scanf("%d",&n); 36 for(int i=1;i<=n;++i) scanf("%d",&w[i]); 37 while(1){ 38 scanf("%d%d",&x,&y); 39 if(!x&&!y) break; 40 add(y,x); 41 exfa[x]=1; 42 } 43 int an=find(); 44 dfs(an); 45 printf("%d ",max(f[an][0],f[an][1])); 46 return 0; 47 }