题面
这道题可以打树上 (DP),但显然贪心方便
我们贪心地考虑这个问题,一个叶子结点的消防站必然是建在它的爷爷上,才能尽可能多的增加覆盖的点,所以先跑一遍 (DFS) 处理深度,再按深度降序扫描节点即可。
时间复杂度:(O(n^2)),可以通过本题。
代码:
// no greater than 2 -> father and grandfather
# include <iostream>
# include <cstdio>
# include <queue>
# define sp std::pair
# define mp std::make_pair
# define MAXN 1005
struct edge{
int v, next;
}e[MAXN<<1];
struct node{
int dep, fa;
}nd[MAXN];
int hd[MAXN], cntE;
bool vis[MAXN];
std::priority_queue<sp<int, int>, std::vector<sp<int, int> >, std::less<sp<int, int> > >Q;
// pair<dep, id>
void AddE(int u, int v);
void PreDFS(int now, int fa);
void AnsDFS(int now, int dis);
int main(){
int n, ans = 0;
scanf("%d", &n);
for(int i = 2, x; i <= n; i++){
scanf("%d", &x);
AddE(i, x); AddE(x, i);
}
PreDFS(1, 0);
int now = Q.top().second;
while(Q.size()){
while(vis[now = Q.top().second] && Q.size()){
Q.pop();
}
if(Q.empty()){
break;
}
if(nd[nd[now].fa].fa){
AnsDFS(nd[nd[now].fa].fa, 0);
}
else{
AnsDFS(1, 0);
}
ans++;
}
printf("%d", ans);
return 0;
}
void AnsDFS(int now, int dis){
if(dis > 2){
return;
}
vis[now] = 1;
for(int i = hd[now]; i; i = e[i].next){
AnsDFS(e[i].v, dis+1);
}
}
void PreDFS(int now, int fa){
nd[now] = (node){nd[fa].dep+1, fa};
Q.push(mp(nd[now].dep, now));
for(int i = hd[now]; i; i = e[i].next){
if(e[i].v == fa){
continue;
}
PreDFS(e[i].v, now);
}
}
void AddE(int u, int v){
e[++cntE] = (edge){v, hd[u]};
hd[u] = cntE;
}