博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树形DP
阅读量:5150 次
发布时间:2019-06-13

本文共 2821 字,大约阅读时间需要 9 分钟。

/*

f[i][0/1] 0与1分别表示第i个人不去,去时的最大快乐指数
所以 f[i][0] += max( f[son][1] ,f[son][0]);
f[i][1] += max(f[son][0] , 0)
1.为什么f[i][1] 要与0 做比较? : 因为快乐指数可能是负的
2. 为什么f[i][0] 不用与0作比较,直接=max?:就算是负的,也只能直接去最大的,他又不去... 

3.为什么是+=? : 下面有

*/

1 #include 
2 #include
3 using namespace std; 4 const int MAXN = 6000+9; 5 6 int n,cnt; 7 int head[MAXN]; 8 int R[MAXN],f[MAXN][2],fa[MAXN]; 9 10 struct edge{11 int y,next;12 }e[MAXN];13 14 void add_edge(int x, int y) {15 e[++cnt].y = y;16 e[cnt].next = head[x];17 head[x] = cnt;18 }19 20 void dfs(int now) {21 f[now][1] = R[now];22 f[now][0] = 0;//初始化23 for(int i = head[now]; i; i = e[i].next ) {
//i是边编号 24 int nn = e[i].y ;25 dfs(nn);//先递归进去处理儿子的f值 26 f[now][0] += max(f[nn][1] ,f[nn][0]) ;27 f[now][1] += max(f[nn][0] , 0);28 //注:因为一棵树可能有多个儿子,所以这里都是+=; 29 }30 }31 32 int main() {33 scanf("%d",&n);34 for(int i = 1; i <= n; i++) {35 scanf("%d",&R[i]);36 }37 int l,k;38 for(int i = 1; i <= n; i++) {39 scanf("%d%d",&l,&k);40 if(i == n) break;//只输入了n-1行 41 fa[l] = k;42 add_edge(k,l);43 }44 int root;45 for(int i = 1; i <= n; i++) if(!fa[i]) {46 root = i;47 break;//找根48 }49 dfs(root);50 int ans = max(f[root][0],f[root][1]);51 printf("%d",ans);52 }

类似的组题(非常好

注: 因为相当于0-1背包中的选或不选,所以 j 是逆序的,其他细节在代码里有体现和解释

1 #include
2 #include
3 using namespace std; 4 const int MAXN = 100+9; 5 6 int n,Q; 7 int f[MAXN][MAXN];//f[i][j]表示: 点i和它的子树保留j个树枝时的最大苹果数 8 int head[MAXN],cnt; 9 10 struct edge{11 int y,val,next;12 }e[MAXN];13 14 void add_edge(int x, int y, int val) {15 e[++cnt].y = y;16 e[cnt].val = val;17 e[cnt].next = head[x];18 head[x] = cnt;19 } 20 21 void dfs(int now ,int dad) {22 f[now][0] = 0;//初始化边界23 for(int i = head[now]; i; i = e[i].next ) {24 int nn = e[i].y ;25 if(nn == dad) continue ;//应该是continue吧,不是return ; 26 dfs(nn, now);//先递归进去处理儿子的f值 27 for(int j = Q; j; j--) {
//逆序的原因: 0-1背包选或不选 28 for(int k = 0; k < j; k++) {
//枚举 左/右 子树保留的树枝29 f[now][j] = max(f[now][j], f[now][j-k-1] + f[nn][k] + e[i].val );30 //要选子树nn上边,就要把子树nn与根的边选上,所以这里是j-k还要"-1" 31 }32 }33 }34 }35 36 int main() {37 scanf("%d%d",&n,&Q);38 int m = n-1;//二叉树的边 39 for(int i = 1, x, y, val; i <= m; i++) {40 scanf("%d%d%d",&x,&y,&val);41 add_edge(x,y,val);42 add_edge(y,x,val);//只是描述了边,但不知道父亲是谁,儿子是谁,所以建双向的43 //所以下面的dfs要开一个树根的形参,防止死循环 44 }45 //1为根46 dfs(1,1);47 printf("%d",f[1][Q]);48 return 0;49 }

 

转载于:https://www.cnblogs.com/tyner/p/10805494.html

你可能感兴趣的文章
第6章 Overlapped I/O, 在你身后变戏法 ---被激发的 Event 对象 -4
查看>>
植物大战僵尸中文年度版
查看>>
26、linux 几个C函数,nanosleep,lstat,unlink
查看>>
001.RAID简介
查看>>
投标项目的脚本练习2
查看>>
第五次实验
查看>>
201521123107 《Java程序设计》第9周学习总结
查看>>
runtime的基本应用
查看>>
localStorage,最简单的历史记录
查看>>
关于scrollTop的那些事
查看>>
Caroline--chochukmo
查看>>
算法导论笔记 第8章 线性时间排序
查看>>
利用jquery的contains实现搜索功能
查看>>
Xcode 6.2 beta 3 太难下载!下载了,不敢独享
查看>>
并发编程
查看>>
Django框架(七)
查看>>
Linux文件系统概述
查看>>
ffmpeg-php
查看>>
别把淘宝客当傻子
查看>>
MySQL 数据库性能优化之SQL优化
查看>>