[HNOI2003]消防局的设立

题目:洛谷P2279、BZOJ1217。

题目大意:一棵树上建立消防局,每个消防局能管到范围2以内的所有节点,问至少建立多少个消防局能管理到所有节点?

解题思路:很神奇的贪心思路。

首先,我们得保证深度大的节点能被覆盖,那么每次要选一个深度最大的节点进行考虑。dfs+排序即可。

然后,为了让一个消防局发挥最大的威力,我们把它设在当前节点的爷爷上,这样既可以管理到当前节点,又可以管理其他更多节点。

再然后就是处理已经被覆盖的节点,如果该节点已经被覆盖,则不用考虑。

覆盖时注意考虑全面。别的就没有了。

时间复杂度看你的排序,数据小$O(n^2)$也行,我用了优先队列(:o)。

C++ Code:

#include<cstdio>
#include<vector>
#include<cstring>
#include<ext/pb_ds/priority_queue.hpp>
int n,ans,fa[1020];
bool vis[1020];
std::vector<int>e[1020];
struct node{
	int dep,num;
	bool operator <(const node& rhs)const{return dep<rhs.dep;}
}p[1020];
__gnu_pbds::priority_queue<node>q;
void dfs(int now){
	for(int i=e[now].size()-1;i>=0;--i)
	if(p[e[now][i]].dep==-1){
		p[e[now][i]]=(node){p[now].dep+1,e[now][i]};
		q.push(p[e[now][i]]);
		dfs(e[now][i]);
	}
}
int main(){
	ans=0;
	scanf("%d",&n);
	memset(p,-1,sizeof p);
	for(int i=2;i<=n;++i){
		scanf("%d",&fa[i]);
		e[fa[i]].push_back(i);
	}
	p[1]=(node){1,1};
	q.push(p[1]);
	dfs(1);
	memset(vis,0,sizeof vis);
	while(!q.empty()){
		node now=q.top();
		q.pop();
		if(!vis[now.num]){
			++ans;
			//----------------------------------------------------------------
			int rt=fa[fa[now.num]];
			vis[rt]=vis[fa[rt]]=vis[fa[fa[rt]]]=true;
			for(int i=e[rt].size()-1;i>=0;--i){
				vis[e[rt][i]]=true;
				for(int j=e[e[rt][i]].size()-1;j>=0;--j)
				vis[e[e[rt][i]][j]]=true;
			}
			//-----father's father's son and father's father's son's sons-----
			rt=fa[rt];
			vis[fa[rt]]=vis[rt]=true;
			for(int i=e[rt].size()-1;i>=0;--i)
			vis[e[rt][i]]=true;
			//--------grandfather's grandfather and grandfather's sons--------
		}
	}
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Mrsrz/p/7718227.html