标签:ARC116E 消防站 int 题解 read while return include
贪心 + 二分。
二分 \(mid\),计算最少需要多少个消防站。
首先对点的深度 \(dep\) 进行排序,每次取当前最深的点 \(v\)。
找到与 \(v\) 的距离为 \(mid\) 的祖先 \(u\),设立消防站。
可以证明这样是最优的:离 \(v\) 最近的消防站一定在 \(u\) 的子树中,并且能覆盖的点小于等于 \(u\) 能覆盖的点。
然后将 \(u\) 能覆盖的点都打上标记,跳到下一个 \(v\)。如果 \(v\) 已经被覆盖了就 \(continue\)。
至于为什么要取最深的点,感性理解一下,越深的点就越难满足要求。
放代码。
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
inline int read(){
int x=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0' && c<='9') x=x*10+c-'0',c=getchar();
return x;
}
int n,k,cnt,head[200002];
struct edge{
int to,nxt;
}e[500002];
void addedge(int A,int B) {
e[++cnt].to=B;
e[cnt].nxt=head[A];
head[A]=cnt;
}
int fa[200002],id[200002],dep[200002];
void dfs(int u,int f) {
fa[u]=f,id[u]=u,dep[u]=dep[f]+1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].to;
if(v==f) continue;
dfs(v,u);
}
}
bool cmp(int x,int y) {
return dep[x]>dep[y];
}
bool vis[200002];
void solve(int u,int d,int f,int x) {
if(d>x) return ;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt) {
int v=e[i].to;
if(v==f) continue;
solve(v,d+1,u,x);
}
}
bool check(int x) {
for(int i=1;i<=n;i++) vis[i]=0;
int tot=0;
for(int i=1;i<=n;i++)
if(!vis[id[i]]) {
tot++;
if(tot>k) return 0;
int u=id[i],dis=x;
while(dis && fa[u]) u=fa[u],dis--;
solve(u,0,0,x);
}
return 1;
}
int main() {
n=read(),k=read();
for(int i=1;i<n;i++) {
int u=read(),v=read();
addedge(u,v),addedge(v,u);
}
dfs(1,0);
sort(id+1,id+n+1,cmp);
int l=1,r=dep[id[1]],ans=r;
while(l<=r) {
int mid=(l+r)/2;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
printf("%d\n",ans);
return 0;
}
标签:ARC116E,消防站,int,题解,read,while,return,include 来源: https://www.cnblogs.com/Sharing666/p/16537225.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。