树上背包?
问最少断掉多少条边可以形成节点数为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.
很好的treedp,一般来说,treedp都是先dfs再回来做dp……
总的复杂度O(n^3);题目其实不难,多想想就好