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为偶数时共取k / 2次叶子,k为奇数时取k / 2次叶子,最后多取一个。
拓扑的思想,记录每个点的深度来判断某个叶子是不是前k / 2个叶子,每取一个叶子将它连接的顶点度数--
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int N = 2e6 + 10;
vector<int>mp[N];
int deg[N], dep[N];
bool vis[N];
int main() {
int n, k, u, v;
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++i) mp[i].clear();
for(int i = 1; i <= n; ++i) deg[i] = 0;
for(int i = 1; i <= n; ++i) dep[i] = 0;
for(int i = 1; i <= n; ++i) vis[i] = 0;
for(int i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
mp[u].push_back(v);
mp[v].push_back(u);
deg[u]++, deg[v]++;
}
if(k < 2) {
printf("%d\n", k);
return 0;
}
queue<int>q;
for(int i = 1; i <= n; ++i)
if(deg[i] == 1) q.push(i), dep[i] = 1;
int ans = 0;
while(!q.empty()) {
int top = q.front();
q.pop();
ans++;
int siz = mp[top].size();
for(int i = 0; i < siz; ++i) {
int to = mp[top][i];
dep[to] = max(dep[to], dep[top] + 1);
if(dep[to] <= k / 2 && --deg[to] == 1) q.push(to);
}
}
printf("%d\n", min(n, ans + k % 2));
return 0;
}