一开始状态定义错了……所以没有对qwq,以及有几个坑qwq……
首先 f [ i ] [ j ] 表示以 i 为根的子树,切除 j 个节点所需要切除的最小边数,而我一开始定义的是表示以 i 为根的子树,切除后生成一颗有 j 个节点的子树,所需要切除的最小边数。
为什么我的不行呐?因为对于一个新的子节点更新状态,它能生成多大的子树其实是和父亲节点是没有关系的,即它与父亲节点原来的状态无关也,两棵树不也连通,然而对于切除多少点,我们在意的是切除后剩的,而不是切除的。那么最后的ans就是 f [ ... ] [ num - p ] + f [ ... ] [ num [ ... ] ]了。
以及,根节点的 f [ ] num是0,因为它没有父亲节点本身就是一颗含有 num 个点的(子)树。
代码如下:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; #define maxn 2000 struct node { int to,nxt; } edge[maxn]; int f[maxn][maxn],num[maxn],head[maxn]; int n,p,cnt,ans=999999999; void add(int a,int b) { edge[++cnt].to=b; edge[cnt].nxt=head[a]; head[a]=cnt; } void dfs(int u,int fa) { num[u]=1; for(int i=head[u]; i; i=edge[i].nxt) { int tot=0,am=0; int v=edge[i].to; if(v==fa) continue; dfs(v,u); num[u]+=num[v]; f[u][num[v]]=1; am+=num[v]; f[u][am]=++tot; } f[u][num[u]]=1; f[u][0]=0; if(u==1) f[u][num[u]]=0; } void dp(int u,int fa) { for(int i=head[u]; i; i=edge[i].nxt) { int v=edge[i].to; if(v==fa) continue; dp(v,u); for(int j=num[u]; j>=0; j--) for(int k=0; k<=j; k++) f[u][j]=min(f[u][j],f[u][j-k]+f[v][k]); } if(num[u]>=p) ans=min(ans,f[u][num[u]-p]+f[u][num[u]]); } int main() { memset(f,0x3f3f3f3f,sizeof(f)); scanf("%d%d",&n,&p); for(int i=1; i<n; i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); dp(1,0); printf("%d",ans); return 0; }