CodeForces - 1042F Leaf Sets

题面

题意

给出一棵树,要求将其叶子分成几个集合,要求每个集合中叶子两两之间的距离不大于k,求至少要将其分成几个集合。

做法

因为n很大,所以考虑贪心。
首先dfs,我们可以自下而上逐个子树考虑,对于一个子树,可以将其拆成几条链,可以将较短的几条链合并在一起,而长的链独自一个集合,然后其父节点与短链集合相连,这样可以保证答案较优。
具体见代码,比较难描述。

代码

#include
#include
#include
#include
#include
#define N 1001000
using namespace std;

int n,m,first[N],bb,ds[N],ans;
struct Bn
{
	int to,next;
}bn[N<<1];

inline void add(int u,int v)
{
	bb++;
	bn[bb].to=v;
	bn[bb].next=first[u];
	first[u]=bb;
}

int dfs(int now,int last)
{
	if(ds[now]==1) return 0;
	int i,j,p,q,t;
	vector<int>use;
	use.clear();
	for(p=first[now];p!=-1;p=bn[p].next)
	{
		if(bn[p].to==last) continue;
		use.push_back(dfs(bn[p].to,now)+1);
	}
	sort(use.begin(),use.end());
	for(i=use.size()-1;i>=0;i--)
	{
		t=use[i];
		if(i) t+=use[i-1];
		if(t<=m) return use[i];
		ans++;
	}
	return -N;
}

int main()
{
	memset(first,-1,sizeof(first));
	int i,j,p,q;
	cin>>n>>m;
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&p,&q);
		add(p,q),add(q,p);
		ds[p]++,ds[q]++;
	}
	for(i=1;i<=n;i++) if(ds[i]>1) break;
	if(dfs(i,-1)>0) ans++;
	cout<<ans;
}

你可能感兴趣的:(贪心,树,经典,技巧)