题意:给你一棵节点为n的树,问至少砍几刀可以孤立出一棵节点为m的子树。
分析:我的树形DP还不是很熟,所以也是看了别人的题解才勉强写了出来。
http://www.cnblogs.com/yu-chao/archive/2011/07/18/2109730.html
就是这个网址大家如果看不懂我的就去看这个吧。
首先这题一看就是树形DP(就不告诉你为什么)。用f[x,j]表示以节点x为根要留j个节点(包括x)需要砍多少刀。首先f[x,1]=x的儿子数量。对于x的一个儿子y,若要在以y为根的树上保留k个节点,则f[x,j]=min(f[y,k]+f[x,j-k])-1,至于为什么要减1,是因为在之前的状态都是从f[x,1]推过来的,然后f[x,1]默认的是所有子树都被砍了,所以在之前的状态中以y为根的树都是被砍掉的,所以现在要接回去,也就是-1(好绕)。
搞定之后还有一件事要注意:最后剩下的树不一定是以原本的根节点为根节点,所以还要把所有节点都找一遍。
代码:
var n,p,i,x,y,root,ans:longint; s:array[1..150] of longint; a:array[0..150,0..150] of longint; f:array[1..150,1..150] of longint; v:array[1..150] of boolean; function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end; procedure dfs(x:longint); var i,j,k:longint; begin for i:=1 to a[x,0] do dfs(a[x,i]); f[x,1]:=a[x,0]; s[x]:=1; for i:=1 to a[x,0] do s[x]:=s[x]+s[a[x,i]]; for i:=1 to a[x,0] do for j:=s[x] downto 2 do for k:=1 to min(j-1,s[a[x,i]]) do if f[a[x,i],k]+f[x,j-k]-1<f[x,j] then f[x,j]:=f[a[x,i],k]+f[x,j-k]-1; end; begin readln(n,p); fillchar(f,sizeof(f),$7f div 10); fillchar(v,sizeof(v),true); fillchar(a,sizeof(a),0); for i:=1 to n-1 do begin readln(x,y); inc(a[x,0]); a[x,a[x,0]]:=y; v[y]:=false; end; for i:=1 to n do if v[i] then begin root:=i; break; end; dfs(root); ans:=f[root,p]; for i:=1 to n do if f[i,p]+1<ans then ans:=f[i,p]+1; writeln(ans); end.