题意:给出一棵树,问最少切断几条边可以得到有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.
浙公网安备 33010602011771号