[HNOI2003]消防局的设立
P2279 [HNOI2003]消防局的设立
题目大意:
有一棵树,有一些标记节点可以覆盖距离小于 \(2\) 的点,要求所有点都被覆盖,求这些节点个数最小值。
分析:
进行贪心分析:我们标记一个节点时,如果标记了根节点,那么一定是比叶子节点更加优秀的点。
这个贪心很好证明,画个图就可以了。
我们通过深度进行节点的排序,让节点从深到浅排,这样能够更好找到根节点。
定义 \(dis[i]\) 为当前标记距离点 \(i\) 的最短距离。
我们按照 \(dep\) 枚举出儿子节点的 父亲,爷爷,判断最小距离。
如果\(dis > 2\) ,显然这时候定义爷爷为标记节点最优秀,于是我们就进行标记 \(ans++,dis[grandfather]=0\)
然后对爷爷的父亲和爷爷,进行判断最小距离(因为浅节点无法到达深节点,只能直接判断)。
此时不用管儿子节点,因为肯定不能访问(原因同上面括号)
最后输出标记个数即可!
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e3+5;
int n,ans;
int b[N],fa[N],dep[N],dis[N];
bool cmp(int a,int b){return dep[a]>dep[b];}
int main(){
cin>>n;
b[1]=1; dis[1]=dis[0]=N;
for(int i=2,x;i<=n;i++){
scanf("%d",&fa[i]); dep[i]=dep[fa[i]]+1; b[i]=i; dis[i]=N;
}
sort(b+1,b+n+1,cmp);//根节点覆盖更广,因此通过深度进行排序。
for(int i=1;i<=n;i++){
int son=b[i],father=fa[b[i]],grandfather=fa[fa[b[i]]];
dis[son]=min(dis[son],min(dis[father]+1,dis[grandfather]+2));
if(dis[son]>2){
dis[grandfather]=0, ans++;
dis[fa[grandfather]]=min(dis[fa[grandfather]],1);
dis[fa[fa[grandfather]]]=min(dis[fa[fa[grandfather]]],2);
}
}
cout<<ans<<endl;
system("pause");
return 0;
}
不关注的有难了😠😠😠https://b23.tv/hoXKV9