题意:给你一棵树,然后问你最少切多少刀可以剩下p个节点
n,p<=200吧,大概。
又是经典模型,设f[i,j]表示以i为根的子树中,最少去掉多少条边能剩下j个节点。
那么就是分类讨论咯。。
设v是x的子树,x是当前节点
有:
1.不切v子树,那么就有f[i,j]=min(f[i,j],f[i,k]+f[v,j-k]);(0<=k<=j)
2.切,那么直接f[i,j]++就可以了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define inf 2147483647/3
using namespace std;
int i,n,m,p=0;
const int N=1e5+6;
int a[N],go[N],next[N],head[N],f[3000][3000],tot;
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
inline void dfs(int x,int fa)
{
int i,v;
i=head[x];
fo(i,0,p)f[x][i]=inf;
f[x][1]=0;
i=head[x];
while (i)
{
v=go[i];
if (v!=fa)
{
dfs(v,x);
for(int j=p;j>=1;j--)
{
int tmp=f[x][j]+1;
fo(k,0,j)
tmp=min(tmp,f[x][k]+f[v][j-k]);
f[x][j]=tmp;
}
}
i=next[i];
}
}
int main()
{
scanf("%d%d",&n,&p);
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(1,0);
int ans=f[1][p];
fo(i,1,n)
ans=min(ans,f[i][p]+1);
printf("%d\n",ans);
}