这道题出的其实挺好的
显然是一个树形
d
p
dp
dp问题
最开始想复杂了
后来发现很简单
一直以为是n^3做法
我们用
d
p
u
,
k
dp_{u,k}
dpu,k表示在以
u
u
u为根的子树中,剔除
k
k
k个的最小需要切的边数
那么初值就是
d
p
u
,
1
=
d
u
u
dp_{u,1}=du_u
dpu,1=duu
转移就是
d
p
u
,
k
=
min
{
d
p
v
,
j
+
d
p
u
,
k
−
j
−
2
}
,
v
∈
s
o
n
(
u
)
,
j
≤
k
dp_{u,k}=\min\{dp_{v,j}+dp_{u,k-j}-2\},v\in son(u) ,j\leq k
dpu,k=min{dpv,j+dpu,k−j−2},v∈son(u),j≤k
注意我们为什么需要
−
2
-2
−2呢,因为我们在
u
,
v
u,v
u,v这里先是默认把他删掉了,然后我们再把他连上,所以要
−
2
-2
−2
答案就是
min
{
d
p
u
,
p
}
\min\{dp_{u,p}\}
min{dpu,p}
其实就是背包嘛
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=205;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,p;
int head[N],cnt;
int f[N][N],ans=INT_MAX;
int siz[N],du[N];
struct Edge{
int to,next;
}e[N*N];
void add(int x,int y){
e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
}
void dfs(int u,int fa){
siz[u]=1,f[u][1]=du[u];
RepG(i,u){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u);
_Rep(k,min(siz[u],p),1)
for(int j=1;j<=siz[v]&&j+k<=p;j++)
f[u][k+j]=min(f[u][k+j],f[u][k]+f[v][j]-2);
siz[u]+=siz[v];
}
ans=min(ans,f[u][p]);
}
int main()
{
memset(head,-1,sizeof(head));
memset(f,0x3f,sizeof(f));
read(n),read(p);
if(n==1)return puts("0"),0;
if(!p)return puts("0"),0;
Rep(i,1,n-1){
int x,y;
read(x),read(y);
du[x]++,du[y]++;
add(x,y),add(y,x);
}
dfs(1,0);
printf("%d\n",ans);
return 0;
}