关于我的AC代码被我自己叉掉这档事
查看原帖
关于我的AC代码被我自己叉掉这档事
51376
MyukiyoMekyaZJunior楼主2020/5/1 10:29

我一开始写了个错误的解法,但是AC了。。。

大致思路是用 cntu,icnt_{u,i} 表示在 uu 节点抛弃 ii 个子树内节点有多少边可以选择,然后对于每个点做一遍背包就行,不需要依赖子节点的背包数组值

但是这个存在问题,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

*/
2020/5/1 10:29
加载中...