博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门
阅读量:5815 次
发布时间:2019-06-18

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

dp这一方面的题我都不是很会,所以来练(xue)习(xi),大概把这题弄懂了。

树形dp就是在原本线性上dp改成了在 '树' 这个数据结构上dp。

一般来说,树形dp利用dfs在回溯时进行更新,使用儿子节点对父亲节点进行更新。

树形dp很多题需要在二叉树上进行。

进入正题。

这个图是洛谷题面里奇奇怪怪的东西,格式弄好就这样。

题意:有一棵已知根(1)的二叉树,每条边都有一个权值,现在可以保留 q 条边,问在这样的前提下,以 1 为根 的树最多能有多少权值和。

题意可以画个图来解释

这个就是样例的图,假设我萌只保留 1-->3 这条边,辣么我萌得到的权值是 1-->3 这条边的权值。

         假设我萌只断掉 1-->3 这条边,辣么可以得到的权值只有1-->4这条边,因为如果1-->3没了,2,5节点无法连通到1,

                3-->2   3-->5 的边也就不是以1为根的树里的了。

 思路:这题看到了二叉树,于是可以往dp方向思考一下,发现是可行的。

           首先可以把所以边的权值下移到节点上,这样我萌列出转移方程。

           设f[i,j]表示以 i 为根的子树中,保留了 j  个节点得到的最大权值。

     设 i 的左儿子为son[i,1] 右儿子为son[i,2] 设权值下移后 x 节点的权值为cost[x]

   则对于 某个节点  x 来说,有三种选择,一是选了左儿子这个点,不选右儿子。

                                                                           二是选了右儿子这个点,不选左儿子。

                      三是既选左儿子又选右儿子。

辣么分别列出转移方程: ① f[i,j]=max(f[son[i,1],j-1]+cost[son[i,1]])  (如果选了son[i,1]则把该权值加上,因为枚举的 j 表示的是保留 个节点,所以要保留son[i,1]的情况下,就要找他的前驱状态 j-1 )

            ② f[i,j]=max(f[son[i,2],j-1]+cost[son[i,2]]) (这个和①是类似的,只是将左儿子改为右儿子)

            ③ f[i,j]=max(f[son[i,1],k]+f[son[i,2],j-2-k]+cost[son[i,1]+cost[son[i,2]) (这个看起来就要复杂得多,我萌画图看看)

 

这样的话应该会很清晰了,辣么肿么去跑这个dp捏。

显然我萌要先做一个预处理,用递归先把 cost[i] son[i,1] son[i,2] 预处理出来。

然后在用一个dfs递归进行dp。 对于 ①②两种情况可以在遍历边的时候直接进行更新,但是对于③情况要在边遍历完后进行。

为什么? 由于递归的顺序。比如样例这个图,他的顺序是这样的   1-->3-->2 好这里可以对2节点的f[2,j]进行更新了

                  然后 1-->3-->2-->3(回溯同时用2节点的信息进行①情况的更新)-->5-->3(此时3的边都遍历完了,先是用5节点的信息进行②情况的更新,然后再使用 2 和 5 的节点信息一起对3进行③情况更新)-->1(类似,用3对1进行①情况的更新) -->4-->1(类似,用4对1进行②情况的更新,用3 4对1进行③情况更新)

这样就应该理解为什么要先把边遍历完才更新③情况了,因为只有这样,要更新的节点的左右儿子的信息才是都已知的,这样才能更新,满足了dp需要利用前驱信息。

1 type 2   node=record 3       y,z:longint; 4       next:longint; 5   end; 6 var num,father,first,cost:array[0..150]of longint; 7     son:Array[0..150,0..2]of longint; 8     i:longint; 9     n,q:longint;10     x,y,z:longint;11     tot:longint;12     e:Array[0..250]of node;13     f:array[0..150,0..150]of longint;14 function max(a,b:longint):longint;15 begin16   if a>b then exit(a) else exit(b);17 end;18 procedure adde(x,y,z:longint);19 begin20   e[tot].next:=first[x];21   e[tot].y:=y;22   e[tot].z:=z;23   first[x]:=tot;24   inc(tot);25 end;26 procedure buildtree(x:longint);27 var i,y:longint;28 begin29   i:=first[x];30   while i<>-1 do31   begin32     y:=e[i].y;33     if father[y]=0 then34     begin35       father[y]:=x;36       cost[y]:=e[i].z;37       inc(num[x]);38       son[x,num[x]]:=y;39       buildtree(y);40     end;41     i:=e[i].next;42   end;43 end;44 procedure dfs(x:longint);45 var i,j:longint;46     l,r,y:longint;47 begin48   for i:=1 to num[x] do49   begin50     y:=son[x,i];51     dfs(y);52     for j:=1 to q do53     f[x,j]:=max(f[x,j],f[y,j-1]+cost[y]);54   end;55   l:=son[x,1];56   r:=son[x,2];57   for i:=1 to q do58     for j:=0 to i-2 do59     f[x,i]:=max(f[x,i],f[l,j]+f[r,i-2-j]+cost[l]+cost[r]);60 end;61 begin62   read(n,q);63   for i:=1 to n do64   first[i]:=-1;65   for i:=1 to n-1 do66   begin67     read(x,y,z);68     adde(x,y,z);69     adde(y,x,z);70   end;71   father[1]:=1;72   buildtree(1);73   dfs(1);74   writeln(f[1,q]);75 end.
树形dp

这题的话,我理解了挺久的,然后理解后直接就敲了一个代码,然后一次过了,所以理解有时候会让代码更快实现。

版权声明:要转载请在评论区留言=v=

转载于:https://www.cnblogs.com/Bunnycxk/p/7356744.html

你可能感兴趣的文章
【SAP HANA】关于SAP HANA中带层次结构的计算视图Cacultation View创建、激活状况下在系统中生成对象的研究...
查看>>
[nodejs] nodejs开发个人博客(五)分配数据
查看>>
《Linux内核修炼之道》 之 高效学习Linux内核
查看>>
Java数据持久层框架 MyBatis之API学习九(SQL语句构建器详解)
查看>>
30分钟Git命令“从入门到放弃”
查看>>
nginx : TCP代理和负载均衡的stream模块
查看>>
MYSQL数据库间同步数据
查看>>
DevOps 前世今生 | mPaaS 线上直播 CodeHub #1 回顾
查看>>
iOS 解决UITabelView刷新闪动
查看>>
让前端小姐姐愉快地开发表单
查看>>
Dubbo笔记(四)
查看>>
Web前端JQuery入门实战案例
查看>>
java B2B2C Springboot电子商城系统- SSO单点登录之OAuth2.0 登出流程(3)
查看>>
USB 通信原理
查看>>
7zZip zip RAR iOS
查看>>
date命令的详细用法!
查看>>
UiAutomator源码分析之UiAutomatorBridge框架
查看>>
python 开发之selenium
查看>>
Xcode3.2.5中找不到Mac OS X - Command Line Utility -...
查看>>
css的div垂直居中的方法,百分比div垂直居中
查看>>