题目:洛谷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; }