BZOJ1217: [HNOI2003]消防局的设立

Description

2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地。
起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。
如果基地A到基地B至少要经过d条道路的话,我们称基地A到基地B的距离为d。
由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。
消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过2的基地的火灾。
你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。

Input

第一行为n,表示火星上基地的数目。N<=1000
接下来的n-1行每行有一个正整数,其中文件第i行的正整数为a[i],表示从编号为i的基地到编号为a[i]的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有a[i] < i

Output

仅有一个正整数,表示至少要设立多少个消防局才有能力及时扑灭任何基地发生的火灾。

Sample Input

6
1
2
3
4
5

Sample Output

2

题解Here!

各大神犇都用的是树形$DP$。。。

不会树形$DP$的我瑟瑟发抖。。。

其实是一个贪心:找最低没被覆盖到的点,并在它的祖父处设一个消防站。

考虑到这个点的所有子孙后代都已经被覆盖了,因此这时覆盖祖父能盖到更多额外的点,并保证结果不会更差。

很多思路是用$DFS$或堆求取最低节点,实际上没必要,只要预处理出深度(边输入边处理)并排序。

然后碰到已覆盖就跳过,未覆盖就在祖父处设消防站,并且$ans++$即可。

问题在于怎样才能判断这个点覆盖到了没有。

有两种情况很好解决:

1. 儿子或孙子覆盖他:可以在在儿子处设站时就标记它。

2. 父亲或祖父覆盖他:可以用儿子对父亲的映射$fa[i]$来解决。

但是问题在于兄弟:

我们可以用$dis$数组维护$\text{离i最近的消防站到i的距离}$,当$dis[fa[i]]==1$时,就能确定它是否被覆盖。

附:

这种方法的普适性很强,可以解决半径为$k$的最小覆盖问题,而且不用存图。

这时只需要把维护$\text{父亲和爷爷}$改成维护$\text{上位k位祖先}$即可,复杂度$O(NK)$,常数也很小。

然后就可以不用想$DP$。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 1010
using namespace std;
int n,ans=0;
int fa[MAXN],deep[MAXN],rk[MAXN],dis[MAXN];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline bool cmp(const int &p,const int &q){
return deep[p]>deep[q];
}
void work(){
for(int i=1;i<=n;i++){
int w=rk[i],u=fa[w],v=fa[u];
dis[w]=min(dis[w],min(dis[u]+1,dis[v]+2));
if(dis[w]>2){
ans++;
dis[v]=0;
dis[fa[v]]=min(dis[fa[v]],1);
dis[fa[fa[v]]]=min(dis[fa[fa[v]]],2);
}
}
printf("%d\n",ans);
}
void init(){
n=read();
rk[1]=deep[1]=1;
dis[1]=dis[0]=n;
for(int i=2;i<=n;i++){
fa[i]=read();
deep[i]=deep[fa[i]]+1;
rk[i]=i;
dis[i]=n;
}
sort(rk+1,rk+n+1,cmp);
}
int main(){
init();
work();
return 0;
}

BZOJ1217: [HNOI2003]消防局的设立的更多相关文章

  1. bzoj1217: [HNOI2003]消防局的设立 [树形dp]

    Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了 ...

  2. 【BZOJ1217】[HNOI2003]消防局的设立 树形DP

    [BZOJ1217][HNOI2003]消防局的设立 Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地, ...

  3. BZOJ 1217: [HNOI2003]消防局的设立( 贪心 )

    一个简单的贪心, 我们只要考虑2个消防局设立的距离为5时是最好的, 因为利用最充分. 就dfs一遍, 再对根处理一下就可以了. 这道题应该是SGU某道题的简化版...这道题距离只有2, 树型dp应该也 ...

  4. P2279 [HNOI2003]消防局的设立

    P2279 [HNOI2003]消防局的设立考场上想出了贪心策略,但是处理细节时有点问题,gg了.从(当前深度最大的节点)叶子节点往上跳k个,在这里设消防局,并从消防局遍历k个距离,标记上. #inc ...

  5. [HNOI2003]消防局的设立 (贪心)

    [HNOI2003]消防局的设立 题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达, ...

  6. [luogu]P2279 [HNOI2003]消防局的设立[贪心]

    [luogu]P2279 [HNOI2003]消防局的设立 题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两 ...

  7. 【洛谷P2279】[HNOI2003]消防局的设立

    消防局的设立 题目链接 贪心:每次取出深度最大的节点,若没有被覆盖到,要想覆盖它, 最优的做法显然是将它的爷爷设为消防局 (因为该节点深度为最大,选兄弟.父亲所覆盖的节点,选了爷爷后都能够覆盖) 用优 ...

  8. BZOJ1217或洛谷2279 [HNOI2003]消防局的设立

    BZOJ原题链接 洛谷原题链接 该题有两种做法,树形\(DP\)和贪心. 先讲贪心. 先将所有点按深度从大到小排序,然后从大到小依次取出点,若已经被覆盖则跳过,否则就在它的祖父点建立消防站. 考虑如何 ...

  9. BZOJ1217:[HNOI2003]消防局的设立

    我对贪心的理解:https://www.cnblogs.com/AKMer/p/9776293.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem ...

随机推荐

  1. POJ 3480 John [博弈之Nim 与 Anti-Nim]

    Nim游戏:有n堆石子,每堆个数不一,两人依次捡石子,每次只能从一堆中至少捡一个.捡走最后一个石子胜. 先手胜负:将所有堆的石子数进行异或(xor),最后值为0则先手输,否则先手胜. ======== ...

  2. readis 内部数据结构

    与其他key-value数据库不同之处 不仅支持字符串值,还支持 字符串 set,get 列表 lpush,rpush,lrange 哈希 hset,hget,hgetall hmset,hmget ...

  3. ReactiveCocoa 迎接下一个更加美好的世界

    什么是ReactiveCocoa 如果你有看Github的Trending Objective-C榜单,那你肯定是见过ReactiveCocoa了.如果你在weibo上关注唐巧.onevcat等国内一 ...

  4. Scut游戏服务器引擎5.6.3.5发布

    版本:5.6.3.5 (2013-11-25) 1. 优化实体ChangeKey队列,减少写库IO(默认为5分钟写入一次数据库) 2. 优化Protobuf序列化启用自动GZip压缩,减少Redis内 ...

  5. Cannot create JDBC driver of class '' for connect URL 'null'问题解决方法2

    1)启动Tomcat服务器,打开浏览器,输入http://localhost:8080/admin(其中localhost是名称服务器或称为主机),进入管理界面的登陆页面,这时候请输入原来安装时要求输 ...

  6. [Golang] 从零開始写Socket Server(2): 自己定义通讯协议

    在上一章我们做出来一个最基础的demo后,已经能够初步实现Server和Client之间的信息交流了~ 这一章我会介绍一下怎么在Server和Client之间实现一个简单的通讯协议.从而增强整个信息交 ...

  7. Codeforces Round #277.5 (Div. 2)(C题)

    C. Given Length and Sum of Digits... time limit per test 1 second memory limit per test 256 megabyte ...

  8. Solidworks如何圆周阵列

    如图所示,我要把一个圆孔分布八个,切记要选择边线,选择等间距,然后输入8,则自动会变成360度.   最后效果如图所示

  9. C 命令行参数

    C 命令行参数 执行程序时,可以从命令行传值给 C 程序.这些值被称为命令行参数,它们对程序很重要,特别是当您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了. 命令行参数是使用 ...

  10. iOS的URLScheme

    一直都有接触要设置app的url scheme,从最早的facebook開始. 当时的理解是SSO用的,当授权成功之后,facebook app或者safari能够利用给定的url scheme来回调 ...