B2. Maximum Control (medium) 树形dp

62 篇文章 0 订阅

题目链接:http://codeforces.com/problemset/problem/958/B2

 

题意:

     你现在有一棵n个点的树,有若干个地标,你可以把这些地标放在树的结点上,被地标占的结点和每两个地标之间的简单路径上的结点都标红,现在问你,假设你有1,2,3....,n个地标时,最多有多少结点可以被染红。

做法:

    很明显你会发现,一定是叶子结点被占用的时候才会染最多的地标,假设叶子结点的数量为x,当你有x个地标时也就做完了,现在的问题时,当你把叶子结点放上的时候,会有一串的结点都可以被忽略,你也会发现,两个地标时能染红的数量就是树的直径。

    你会发现,假设我们从树直径上的一个点走,每遇到一个分叉,都会增加一个新的叶子,而每个叶子又可以当做是一个新的数,新的数上找深度最大的儿子结点,就是这个树假设没有分叉的贡献。

    那么我们就可以用dp来做,dp[i]表示以结点i为根,它的最长儿子链+1(它自己),除最长儿子链以外的结点的dp,就又是一个新的可加值,所有的可加值从大到小取,就是我们要的顺序。


#include<bits/stdc++.h>
using namespace std;
const int maxn=100005;
int n,dp[maxn],more[maxn],now,cnt,ans[maxn];
struct edge{
    int v,next;
}e[maxn<<1];
int head[maxn],rt,dep[maxn],son[maxn];
void add(int u,int v){
    e[cnt].v=v, e[cnt].next=head[u];
    head[u]=cnt++;
}
void dfs(int u,int fa){
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        dep[v]=dep[u]+1;
        dfs(v,u);
    }
    if(dep[u]>dep[rt]) rt=u;
}
void Dpdfs(int u,int fa){
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        Dpdfs(v,u);
        if(dp[v]>dp[son[u]]) son[u]=v;
    }
    dp[u]=dp[son[u]]+1;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;
        if(v!=fa&&v!=son[u]){
            more[++now]=dp[v];
        }
    }
}
bool cmp(int a,int b){return a>b;}
int main(){
    memset(head,-1,sizeof(head));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    dfs(1,0);
    Dpdfs(rt,-1);
    more[++now]=dp[rt];
    sort(more+1,more+1+now,cmp);
    for(int i=1;i<=now;i++){
        ans[i+1]=ans[i]+more[i];
    }
    ans[1]=1;
    for(int i=now+1;i<=n;i++) ans[i]=n;
    for(int i=1;i<=n;i++){
        printf("%d%c",ans[i],i==n?'\n':' ');
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值