题意:给出一棵树,问最少切断几条边可以得到有p个结点的子树.
分析:明显的树形DP.f[i,j]表示以第i个节点为根的子树保留j个节点最少需要去掉几条边.
f[i,j]=min{f[i,j-k]+f[s,k]-2} (s是i的儿子)
ans=min{f[i,p]}
code:
type edge=record v,n:longint; end; const root=1; oo=10000; var e:array[0..400] of edge; vis:array[0..200] of boolean; h,s:array[0..200] of longint; t,f:array[0..200,0..200] of longint; g:array[0..200,0..200] of boolean; n,m,i,j,u,v,cnt,ans:longint; procedure add(u,v:longint); begin inc(cnt); e[cnt].v:=v; e[cnt].n:=h[u]; h[u]:=cnt; end; procedure dfs(u:longint); var v,p:longint; begin vis[u]:=true; p:=h[u]; s[u]:=1; while p<>0 do begin v:=e[p].v; if not vis[v] then begin dfs(v); inc(s[u],s[v]); inc(t[u,0]); t[u,t[u,0]]:=v; end; p:=e[p].n; end; end; function min(a,b:longint):longint; begin if a>b then exit(b); exit(a); end; procedure DP(u:longint); var o,p,q,v:longint; begin for o:=1 to t[u,0] do DP(t[u,o]); if u=root then f[u,1]:=t[u,0] else f[u,1]:=t[u,0]+1; for o:=1 to t[u,0] do begin v:=t[u,o]; for p:=s[u] downto 1 do for q:=1 to s[u]-p do f[u,p+q]:=min(f[u,p+q],f[u,p]+f[v,q]-2); end; end; begin readln(n,m); for i:=1 to n-1 do begin readln(u,v); add(u,v); add(v,u); end; dfs(root); for i:=1 to 200 do for j:=0 to 200 do f[i,j]:=oo; DP(root); ans:=oo; for i:=1 to n do ans:=min(ans,f[i,m]); writeln(ans); end.