Codeforces 1249F Maximum Weight Subset (贪心)

题意

在一颗有点权的树上,选若干个点,使得这些点两两距离大于k,且点权和最大

思路

贪心的取比较大的值即可
将所有点按照深度从大到小排序,如果当前点点权\(a[i]\)大于0,则将距离为k以内的所有点减\(a[i]\)
代表取了当前点,为答案贡献\(a[i]\)
如果下面又扫到大于零的点权,说明那个点比这个大,于是取那个
复杂度\(O(n^2)\)

代码

int n,k;
int a[maxn],b[maxn];
vector<int>v[maxn];
int ans;
int dep[maxn];
void dfs(int x, int fa, int dp){
    dep[x]=dp;
    for(int i = 0; i < (int)v[x].size(); i++){
        int y = v[x][i];
        if(y==fa)continue;
        dfs(y,x,dp+1);
    }
}int vis[maxn];
int gao(int st){
    for(int i = 1; i <= n; i++)vis[i]=0;
    queue<PI>q;
    q.push(make_pair(st,0));
    int C = a[st];
    while(!q.empty()){
        int x = q.front().fst;
        vis[x]=1;
        a[x]-=C;
        int stp = q.front().sc;
        q.pop();
        if(stp!=k){
            for(int i = 0; i < (int)v[x].size(); i++){
                int y = v[x][i];
                if(!vis[y])q.push(make_pair(y,stp+1));
            }
        }
    }
    return C;
}
bool cmp(int a, int b){return dep[a]>dep[b];}
int main(){
    scanf("%d %d", &n, &k);
    for(int i = 1; i <= n; i++){
        scanf("%d", &a[i]);b[i]=i;
    }
    for(int i = 1; i < n; i++){
        int x,y;
        scanf("%d %d", &x, &y);
        v[x].pb(y);v[y].pb(x);
    }dfs(1,-1,0);
    sort(b+1,b+1+n,cmp);
    for(int i = 1; i <= n; i++){
        if(a[b[i]]>0)ans+=gao(b[i]);
        
        //printf("  %d %d\n",b[i],ans);
    }
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-10-23 15:01  wrjlinkkkkkk  阅读(...)  评论(... 编辑 收藏