题解 P2279 【[HNOI2003]消防局的设立】
zhoutb2333 · · 题解
这题贪心比较好想
考虑当前深度最大的叶子结点,你肯定要有一个消防局去覆盖它,
那么既然他是叶子结点,所以与他距离小于等于2的节点有这么几种:
- 他的父亲 2. 他的兄弟 3. 他的爷爷
容易看出,在前两项能够覆盖到的节点,在爷爷那里设立一定也能覆盖到。
所以每次贪心取出深度最大的节点,在他的爷爷哪里放一个消防站
用STL的priority_queue,时间复杂度O(nlogn)
#include<bits/stdc++.h>
#define maxn 1010
#define maxm 2010
using namespace std;
int head[maxn],point[maxm],nxt[maxm],dep[maxn],fa[maxn],tot=0;
bool vis[maxn];
struct cmp{
bool operator () (int &a,int &b){
return dep[a]<dep[b];
}
};
priority_queue<int,vector<int>,cmp> q;
void add(int x,int y){
point[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int temp,int father,int depth){
fa[temp]=father;
dep[temp]=depth;
for(int j=head[temp];j;j=nxt[j]){
if(point[j]==father)
continue;
dfs(point[j],temp,depth+1);
}
}
void dfs2(int temp,int depth){
if(depth>2)
return;
vis[temp]=true;
for(int j=head[temp];j;j=nxt[j])
dfs2(point[j],depth+1);
}
int main(){
int n,cnt,x,y,ans=0;
scanf("%d",&n),cnt=n;
for(int i=1;i<=n-1;i++)
scanf("%d",&x),add(i+1,x),add(x,i+1);
dfs(1,0,1);
for(int i=1;i<=n;i++)
q.push(i);
while(q.size()){
while(q.size()&&vis[x=q.top()])
q.pop();
if(!q.size())
break;
if(fa[fa[x]])
dfs2(fa[fa[x]],0);
else
dfs2(1,0);
ans++;
}
printf("%d\n",ans);
return 0;
}