题目:洛谷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\n",ans);
return 0;
}