• poj1947


    树上背包?

    问最少断掉多少条边可以形成节点数为k的块

    设f[i,j]表示以节点i为根,形成一个节点数为k的块要断多少条边

    则有:f[x,j]:=min(f[x,j],f[x,j-k]+f[y,k]-2) y是x的孩子

    为什么要减2,现在装入以y为节点的子树,x和y之间的边,这条边自然不用断了,但在计算f[y,k]和f[x,1]的时候,这条边被断了两次

     1 const max=10006;
     2 var f,son:array[0..200,0..200] of longint;
     3     fa,s,t:array[0..200] of longint;
     4     j,x,y,i,n,m,root,ans:longint;
     5 
     6 procedure treedp(x:longint);
     7   var i,y,j,k:longint;
     8   begin
     9     t[x]:=1;
    10     for i:=1 to s[x] do
    11     begin
    12       treedp(son[x,i]);
    13       t[x]:=t[x]+t[son[x,i]];   //先统计子树规模
    14     end;
    15     f[x,1]:=s[x];
    16     if x<>root then inc(f[x,1]);   //细节 注意要断他父亲和它之间的边
    17     for i:=1 to s[x] do
    18     begin
    19       y:=son[x,i];
    20       for j:=t[x] downto 2 do   //注意背包的倒推,每个子树显然只能用一次,相当于01背包
    21         for k:=1 to t[y] do
    22           if j-k>=1 then f[x,j]:=min(f[x,j],f[x,j-k]+f[y,k]-2)
    23           else break;
    24     end;
    25 
    26   end;
    27 
    28 begin
    29   readln(n,m);
    30   for i:=1 to n-1 do
    31   begin
    32     readln(x,y);
    33     s[x]:=s[x]+1;   //题目中给定了父子关系
    34     son[x,s[x]]:=y;
    35     fa[y]:=x;
    36   end;
    37   for i:=1 to n do
    38     for j:=1 to n do
    39       f[i,j]:=max;
    40   root:=1;
    41   while fa[root]<>0 do inc(root);
    42   treedp(root);
    43   ans:=max;
    44   for i:=1 to n do           
    45     ans:=min(ans,f[i,m]);
    46   writeln(ans);
    47 end.
    View Code

    很好的treedp,一般来说,treedp都是先dfs再回来做dp……

    总的复杂度O(n^3);题目其实不难,多想想就好

  • 相关阅读:
    再见 2020, 愿“山河无恙,人间皆安”| 年终总结
    Oracle
    Linux安装
    线程池
    AutoJS
    VSCode
    c++ 解析yaml文件
    管道: 哪些命令能直接从管道的输出中读取?
    K8S 集群部署
    Android项目实战(六十一):pdf文件用图片方式预览
  • 原文地址:https://www.cnblogs.com/phile/p/4473277.html
Copyright © 2020-2023  润新知