传送门:>HERE<
题意:给出一颗树,先要求在一些点上设立消防局。每个消防局能够覆盖与它距离不大于2的其他点。求最少设置几个消防局才能够覆盖所有节点。
解题思路:
贪心:每次选取还没有被覆盖的深度最大的点,在它的爷爷那里设立消防局。
为什么这样是正确的呢?这里有一个很巧妙的思路:由于我目前选择的是没有标记的并且是最深的了,所以肯定不存在还没有标记的但比这个点更深的点了(已经被覆盖的点我们肯定不会去浪费机会再设立了)。因此想要覆盖当前这个最深的点,有三个选择:1.设立在它父亲 2.设立在它兄弟 3.设立在它爷爷
很容易发现,如果设立在了它爷爷那里,一定覆盖了它父亲和它兄弟,因此我们就可以贪心地选择在它爷爷那里设立
Code
细节。不知道为什么在洛谷AC了,在BZOJ却CE了
/*by DennyQi*/ #include <cstdio> #include <queue> #include <algorithm> #include <cstring> #define r read() #define Max(a,b) (((a)>(b))?(a):(b)) #define Min(a,b) (((a)<(b))?(a):(b)) using namespace std; const int MAXN = 1010; const int INF = 0x3f3f3f3f; inline int read(){ int x = 0; int w = 1; register char c = getchar(); while(c ^ '-' && (c < '0' || c > '9')) c = getchar(); if(c == '-') w = -1, c = getchar(); while(c >= '0' && c <= '9') x = (x<<3) + (x<<1) + c - '0', c = getchar(); return x * w; } struct Node{int idx,deep;}a[MAXN]; int N,x,ans,T; int fa[MAXN],mark[MAXN]; vector <int> G[MAXN]; inline bool comp(Node& a, Node& b){ return a.deep > b.deep; } void Dfs(int x, int father, int deep){ int sz = G[x].size(),v; fa[x] = father; a[++T] = (Node){x, deep}; for(int i = 0; i < sz; ++i){ v = G[x][i]; if(v == father) continue; Dfs(v, x, deep+1); } } inline void MarkDown(int u){ ++ans; int sz = G[u].size(),v,__sz; mark[u] = 1; for(int i = 0; i < sz; ++i){ v = G[u][i], mark[v] = 1; __sz = G[v].size(); for(int j = 0; j < __sz; ++j) mark[G[v][j]] = 1; } u = fa[u]; mark[u] = 1, mark[fa[u]] = 1; sz = G[u].size(); for(int i = 0; i < sz; ++i) mark[G[u][i]] = 1; } int main(){ // freopen(".in","r",stdin); N=r; for(int i = 2; i <= N; ++i){ x=r; G[i].push_back(x), G[x].push_back(i); } Dfs(1, 0, 1); sort(a+1,a+T+1,comp); int u,v,sz; for(int i = 1; i <= T; ++i){ u = a[i].idx; if(mark[u]) continue; if(fa[fa[u]]) MarkDown(fa[fa[u]]); else{ if(fa[u]) MarkDown(fa[u]); else MarkDown(u); } } printf("%d", ans); return 0; }