[HNOI2003][树上贪心]消防局的设立

题面

这道题可以打树上 \(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;
}
posted @ 2020-08-24 19:26  ChPu437  阅读(120)  评论(0编辑  收藏  举报