zoukankan      html  css  js  c++  java
  • 洛谷 P2015 二叉苹果树(codevs5565) 树形dp入门

    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 begin
    16   if a>b then exit(a) else exit(b);
    17 end;
    18 procedure adde(x,y,z:longint);
    19 begin
    20   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 begin
    29   i:=first[x];
    30   while i<>-1 do
    31   begin
    32     y:=e[i].y;
    33     if father[y]=0 then
    34     begin
    35       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 begin
    48   for i:=1 to num[x] do
    49   begin
    50     y:=son[x,i];
    51     dfs(y);
    52     for j:=1 to q do
    53     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 do
    58     for j:=0 to i-2 do
    59     f[x,i]:=max(f[x,i],f[l,j]+f[r,i-2-j]+cost[l]+cost[r]);
    60 end;
    61 begin
    62   read(n,q);
    63   for i:=1 to n do
    64   first[i]:=-1;
    65   for i:=1 to n-1 do
    66   begin
    67     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=

  • 相关阅读:
    Binary Tree Inorder Traversal
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Majority Element
    Excel Sheet Column Number
    Reverse Bits
    Happy Number
    House Robber
    Remove Linked List Elements
    Contains Duplicate
  • 原文地址:https://www.cnblogs.com/Bunnycxk/p/7356744.html
Copyright © 2011-2022 走看看