树形DP--codevs 1380 没有上司的舞会
codevs 1380 没有上司的舞会
变式题目:给定一棵树每个点有一个点权,求一个独立集使得点权和最大,树上的独立集指的是选取树上的点,使尽量多的点不直接相连
时间限制: 1 s
空间限制: 128000 KB
题目等级 : 钻石 Diamond
题目描述 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
分类标签 Tags
动态规划 树型DP
1 /*树形Dp:一般以节点作为状态划分的点。 2 对于当前的节点代表的人: 3 1.这个人去舞会,那么他的下属一定不去,状态转移到子节点 4 2.这个人不去舞会,但是他的下属也不一定会去,因为不一定是最优,就是在子节点去与不去间取最优 5 树形Dp一般从根节点开始记忆化搜索来实现。 6 */ 7 #include<iostream> 8 using namespace std; 9 #include<cstdio> 10 #define N 8000 11 struct Edge{ 12 int v,last; 13 }edge[N]; 14 bool flag[N];/*找根节点*/ 15 int f[N][2],val[N];/*f[i][1]代表当前节点去舞会的这棵子树上快乐最大值,f[i][0]代表当前节点不去舞会的这棵子树上快乐最大值,*/ 16 int head[N]={0},cnt=0; 17 int n; 18 void add_edge(int u,int v) 19 { 20 ++cnt; 21 edge[cnt].v=v;/*建立边表*/ 22 edge[cnt].last=head[u]; 23 head[u]=cnt; 24 } 25 void dp(int u) 26 { 27 f[u][0]=0;/*搜索的边界就是没有下属的人,就是f[u][1]=val[u]; f[u][0]=0;*/ 28 f[u][1]=val[u]; 29 for(int l=head[u];l;l=edge[l].last)/*对于有下属的人,必须知道他的下属情况才能判断*/ 30 { 31 int v=edge[l].v; 32 dp(v);/*搜索下属*/ 33 f[u][1]=max(f[u][1],f[u][1]+f[v][0]);/*注意这是在for循环中当前点的f[v][0]会被加了多次,v不同*/ 34 f[u][0]=f[u][0]+max(f[v][1],f[v][0]);/*当前节点不去,就判断他的某个子节点去还是不去最优*/ 35 } 36 } 37 int main() 38 { 39 scanf("%d",&n); 40 for(int i=1;i<=n;++i) 41 scanf("%d",&val[i]); 42 for(int i=1;i<n;++i) 43 { 44 int u,v; 45 scanf("%d%d",&v,&u); 46 flag[v]=true;/*给有父节点的点标上标记*/ 47 add_edge(u,v); 48 } 49 int u,v; 50 scanf("%d%d",&u,&v); 51 for(int i=1;i<=n;++i) 52 if(!flag[i])/*找到根节点*/ 53 { 54 dp(i); 55 printf("%d\n",max(f[i][0],f[i][1])); 56 break; 57 } 58 return 0; 59 }