您的位置:首页 > 其它

[HNOI2003] 消防局的设立

2018-07-28 10:07 411 查看

传送门:>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;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: