Codeforces Round #595 (Div. 3) F - Maximum Weight Subset(贪心)

题意

n(n<=200)个节点的树,树上距离小于等于k(k<=200)的两个点不能同时选,

每个点有个点权ai(1<=ai<=1e5),求最大权重和

题解

Claris的做法,先bfs一遍,然后倒序扫bfs序列,

每次贪心选这个值,并把距离≤k的点都减去这个点的权值,

代表选这个值给别的点带来的不能选的影响,

如果扫到一个点为正,此时代表把残值加上,相当于反选

倒序是因为,只有所有儿子都确定了,父亲才能被确定,是否应该反选

看似是O(n^2)的

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,k,x,y,z,a[N],head[N],cnt;
bool vis[N];
int q[N],h,t,ans;
struct node{int v,nex;}e[N*2];
void add(int u,int v){e[++cnt]=node{v,head[u]};head[u]=cnt;}
void ext(int u)
{
	if(vis[u])return;
	vis[u]=1;
	q[++t]=u;
}
void dfs(int u,int fa,int d)
{
	if(d>k)return;
	a[u]-=z;
	for(int i=head[u];i;i=e[i].nex)
	{
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u,d+1);
	}
}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;++i)
	scanf("%d",&a[i]);
	for(int i=1;i<n;++i)
	{
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	h=1;t=0;
	ext(1);
	while(h<=t)
	{
		x=q[h++];
		for(int i=head[x];i;i=e[i].nex)
		{
			int v=e[i].v;
			ext(v);
		}
	}
	for(int i=n;i;i--)
	{
		x=q[i];
		if(a[x]<=0)continue;
		z=a[x];
		ans+=z;
		dfs(x,0,0);
	}
	printf("%d\n",ans);
	return 0;
}
发布了467 篇原创文章 · 获赞 53 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/102705256
今日推荐