我一开始写了个错误的解法,但是AC了。。。
大致思路是用 cntu,i 表示在 u 节点抛弃 i 个子树内节点有多少边可以选择,然后对于每个点做一遍背包就行,不需要依赖子节点的背包数组值
但是这个存在问题,cnt 内会产生重复
所以请求添加一组hack数据:
Input:
10 4
1 2
2 3
3 4
1 5
1 6
1 7
1 8
1 9
1 10
Output:
4
我的错误AC代码:
// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
using namespace std;
const int MaxN=250;
struct Edge
{
int nxt,to;
}E[MaxN<<2];
template <class t> inline void read(t &s)
{
s=0;
reg int f=1;
reg char c=getchar();
while(!isdigit(c))
{
if(c=='-')
f=-1;
c=getchar();
}
while(isdigit(c))
s=(s<<3)+(s<<1)+(c^48),c=getchar();
s*=f;
return;
}
int hd[MaxN],en,n,p;
int f[MaxN][MaxN],cnt[MaxN][MaxN];
int sons[MaxN];
int ans=1e9,rt;
inline void adde(int u,int v)
{
++en;
E[en]=(Edge){hd[u],v};
hd[u]=en;
return;
}
inline void dfs(int u)
{
sons[u]=1;
for(int i=hd[u];~i;i=E[i].nxt)
{
reg int v=E[i].to;
dfs(v);
sons[u]+=sons[v];
// ++cnt[u][1];
++cnt[u][sons[v]];
for(int i=1;i<=sons[v];++i)
cnt[u][i]+=cnt[v][i];
}
f[u][0]=0;
for(int i=1;i<=sons[u];++i)
for(int j=1;j<=cnt[u][i];++j)
for(int k=sons[u];k>=i;--k)
f[u][k]=min(f[u][k],f[u][k-i]+1);
/*
printf("Node %d: sons %d\n",u,sons[u]);
for(int i=1;i<=n;++i)
printf("%11lld ",f[u][i]);
puts("");
for(int i=1;i<=sons[u];++i)
printf("%d ",cnt[u][i]);
puts("");
*/
if(sons[u]-p>=0&&f[u][sons[u]-p]<0x3f3f3f3f3f3f3f3f)
{
if(u==rt)
ans=min(ans,f[u][sons[u]-p]);
else
ans=min(ans,f[u][sons[u]-p]+1);
}
return;
}
signed main(void)
{
memset(hd,-1,sizeof hd);
memset(f,0x3f,sizeof f);
rt=0;
reg int u,v;
cin>>n>>p;
for(int i=1;i<n;++i)
{
read(u);read(v);
if(!rt)
rt=u;
if(rt==v)
rt=u;
adde(u,v);
// adde(v,u);
}
dfs(rt);
cout<<ans<<endl;
return 0;
}
/*
Submit 1:
5 3
1 2
2 3
2 4
4 5
5 4
1 2
2 3
3 4
4 5
7 7
1 2
1 7
2 3
2 6
3 4
3 5
Submit 2:
Bad
Submit 3:
7 6
1 2
1 3
2 4
2 5
3 6
3 7
*/