EOJ Monthly 2020.9 B. 健康监测计划

B. 健康监测计划

单点时限: 2.0 sec

内存限制: 256 MB

QQ 小方接到了来自学校防控疫情指挥部的任务,协助指挥部部署校园内的健康监测站。

华东师范大学共有 n 栋楼房,编号为 1,2,…,n,并有 n−1 条双向联通的道路连接这些楼房,使得任意两栋楼房之间有且仅有一条简单路径(一条简单路径是指,从一栋大楼出发,不经过重复大楼,并在另一栋大楼结束的路径)。学校为了贯彻落实常态化疫情防控政策,决定选择一些楼房,在其中各设置一个健康监测点,实时监测路过的同学的健康状况。

虽然自动化检查仪器已经在全校普及,但是监测的过程依然不可避免地会影响学生的出入便捷性。所以学校需要精心安排监测点的位置,使得监测点数量尽可能多,而且尽量不对师生们造成太大的麻烦。具体而言,对于任意一条从某一栋楼开始在另一栋楼结束的简单路径,你需要保证路径上的监测点的数量不超过 k(包括起点和终点上的监测点),并在此前提下最大化监测点的数量。

输入格式

第一个输入两个整数 n 和 k(2≤n≤106,0≤k≤n),表示华师大楼房的个数以及任意一条简单路径上的监测点数目上限。

接下来 n−1 行,每行输入两个不同的正整数 u,v(1≤u,v≤n),表示有一条直接连接 u 号楼房和 v 号楼房的双向道路。

输出格式

一行,一个整数,表示最多能放置多少个健康监测站。

样例

input

10 1
1 4
1 2
2 5
2 3
2 7
2 8
5 6
6 10
8 9

output

1

input

8 2
5 1
7 1
2 1
4 7
6 7
8 6
3 4

output

4
思路:考虑k=1的时候,答案是1,k=2的时候,答案是所有叶子结点的个数,k=3的时候,答案是所有叶子结点的个数+1,k=4的时候,答案是所有叶子结点的个数+去掉这些叶子结点之后的叶子结点个数,不难推测出k是偶数的时候,答案是所有深度为小于等于k/2的结点个数总和,k是奇数的时候,答案是深度为小于等于k/2的结点个数+1。

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;

const int maxn = 2e6 + 100;
struct node{
    int to, next;
}edge[2 * maxn];

int n, k;
int cnt = 0;
int head[2 * maxn];
int indegree[maxn];
int cntt[maxn];
int ans[maxn];

void add(int u, int v)
{
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

queue<int>q;
void bfs()
{
    while(!q.empty()){
        int u = q.front();
        q.pop();
        //找到与u相连的边
        for(int i = head[u]; ~i; i = edge[i].next){
            int v = edge[i].to;
                cntt[v] = cntt[u] + 1;
                 //入度为2的时候,减去叶子结点,只剩下一个结点,
                if(--indegree[v]==1){
                    ans[cntt[v]]++;
                    q.push(v);
                }
        }
    }
}

void input()
{
    scanf("%d%d", &n, &k);
    memset(head, -1, sizeof(head));
    for(int i = 1; i < n; i++){
        int u, v;
        scanf("%d%d", &u, &v);
        indegree[u]++, indegree[v]++;
        add(u, v), add(v, u);
    }
}

int main()
{
    input();
    for(int i = 1; i <= n; i++){//找到所有入度为1的结点(叶子节点)
        if(indegree[i] == 1){
            cntt[i] = 1;
            ans[1]++;
            q.push(i);
        }
    }
    bfs();

    int tot = 0;
    for(int i = 1; i <= k / 2; i++){
        tot += ans[i];
    }
    if(k & 1)tot++;
    tot = min(tot, n);
    printf("%d\n", tot);

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值