9

给定 n 个节点 n-1 条边组成的树,以节点 1 为根。现需要选出 k 个节点作为工业城市,其余城市均为旅游城市。问从所有工业城市出发走到根节点所经过的旅游城市数量之和的最大值。
在这里插入图片描述

思路

选出 n-k 个旅游城市
以节点 1 为树根->对于每个节点,我们可以计算出以这个节点为根的子树中包含的节点数量以及这个节点拥有的祖先节点数量。
选择的旅游城市都是尽可能靠近根节点的,首先肯定是将根节点选成旅游城市,then选择某个节点 i 作为旅游城市,那么对答案的“增加的贡献”就是以节点 i 为根的子树节点数量。

点击进入

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<int> G[200050];
bool vis[200050];

struct node
{
    int cnt,dis; //cnt存子树除该节点外的节点数量,dis存节点深度
    bool operator < (const node& a) const
    {
        return cnt-dis>a.cnt-a.dis; //按照对答案的贡献(cnt-dis)从大到小排序
    }
}ar[200050];

int dfs(int pos,int fa)
{
    vis[pos]=true; //标记访问
    ar[pos].dis=ar[fa].dis+1; //节点深度=父节点节点深度+1
    for(int it:G[pos])
        if(!vis[it])
            ar[pos].cnt+=dfs(it,pos); //求除自己以外子树中节点数量之和
    return ar[pos].cnt+1; //返回时要加上自己
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int n,k,a,b;
    cin>>n>>k;
    for(int i=1;i<n;i++)
    {
        cin>>a>>b;
        G[a].push_back(b);
        G[b].push_back(a);
    }
    ar[0].dis=-1; //特殊处理下,dis[1]=dis[0]+1=0 -> dis[0]=-1
    dfs(1,0);
    sort(ar+1,ar+n+1);
    ll ans=0;
    for(int i=1;i<=n-k;i++)
        ans+=ar[i].cnt-ar[i].dis;
    cout<<ans<<'\n';

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值