Description

2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地。起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。如果基地A到基地B至少要经过d条道路的话,我们称基地A到基地B的距离为d。

由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过2的基地的火灾。

你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。

Input

输入文件名为input.txt。

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

Output

输出文件名为output.txt

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

Sample

输入样例#1:

  1. 6
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
输出样例#1:

  1. 2
  2.  
  3. Solution
    方法1:贪心
    转化为一棵以1为根节点的有根树,考虑深度最大的节点,当覆盖它的节点为它的父节点的父节点时,是最优的(反证法)

举个栗子,考虑节点5时,1,3,4都可以覆盖它,但是3,4能覆盖的节点1都可以覆盖(因为3,4的深度小一点,覆盖的点的深度也小一点,但是5是深度最大的点,没有深度更大的点了)

  1. 所以可以以深度为关键字排序,每次找到深度最大的节点,从这个节点出发走4个距离的点都标为已覆盖
  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<cstdlib>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<queue>
  8. #define nn 1011
  9. using namespace std;
  10. int vis[nn],dis[nn],fir[nn],nxt[nn<<1],to[nn<<1],e=0;
  11. struct node{
  12. int th,dis;
  13. bool operator <(const node &v) const{
  14. return dis<v.dis;
  15. }
  16. }o;
  17. priority_queue<node> q;
  18. int read()
  19. {
  20. int ans=0,f=1;char ch=getchar();
  21. while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
  22. while(isdigit(ch)) {ans=ans*10+ch-'0';ch=getchar();}
  23. return ans*f;
  24. }
  25. void add(int u,int v)
  26. {
  27. nxt[++e]=fir[u];fir[u]=e;to[e]=v;
  28. nxt[++e]=fir[v];fir[v]=e;to[e]=u;
  29. }
  30. void solve(int x,int fa,int use)
  31. {
  32. vis[x]=1;
  33. if(use>=4)
  34. return;
  35. for(int i=fir[x];i;i=nxt[i])
  36. if(to[i]!=fa)
  37. solve(to[i],x,use+1);
  38. }
  39. int main()
  40. {
  41. int n,fa,ans=0;
  42. n=read();
  43. o.dis=0;o.th=1; ////
  44. q.push(o);
  45. for(int i=2;i<=n;i++)
  46. {
  47. fa=read();
  48. dis[i]=dis[fa]+1;
  49. o.dis=dis[i];o.th=i;
  50. q.push(o);
  51. add(i,fa);
  52. }
  53. while(!q.empty())
  54. {
  55. o=q.top();q.pop();
  56. if(!vis[o.th])
  57. {
  58. solve(o.th,0,0);
  59. ans++;
  60. }
  61. }
  62. printf("%d",ans);
  63. return 0;
  64. }
  1.  
  2. 方法2:树形dp

洛谷 2279 [HNOI2003]消防局的设立的更多相关文章

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

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

  2. 洛谷 P2279 [HNOI2003]消防局的设立 (树形dp or 贪心)

    一看到这道题就知道是树形dp 之前做过类似的题,只不过保护的范围是1 所以简单很多. 这道题保护的范围是2,就复杂了很多. 我就开始列状态,然后发现竟然有5种 然后我就开始列方程. 但是我考虑的时候是 ...

  3. 洛谷P2279 [HNOI2003]消防局的设立

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

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

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

  5. 洛谷 P2279 [HNOI2003]消防局的设立 题解

    每日一题 day34 打卡 Analysis 这道题的正解本来是树形dp,但要设5个状态,太麻烦了.于是我就用贪心试图做出此题,没想到还真做出来了. 考虑当前深度最大的叶子结点,你肯定要有一个消防局去 ...

  6. Luogu 2279 [HNOI2003]消防局的设立 - 贪心

    Description 给定一棵树形图, 建若干个消防站, 消防站能够覆盖到距离不超过2的点, 求最少需要建几个消防站才能覆盖所有点 Solution 从深度最深的点开始, 在它的爷爷节点上建, 每建 ...

  7. luogu 2279 [HNOI2003]消防局的设立 树形dp

    就是细节多一些,思路都非常常规. Code: #include <bits/stdc++.h> #define N 1005 #define inf 1061109567 #define ...

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

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

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

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

随机推荐

  1. Flask中的session机制

    cookie和sessioncookie:网站中,http请求是无状态的,第一次和服务器连接后并且登陆成功后,第二次请求服务器依然不能知道当前请求是哪个用户.cookie的出现就是解决了改问题,第一次 ...

  2. codevs1214 线段覆盖

    1214 线段覆盖 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold       题目描述 Description 给定x轴上的N(0<N<100)条线段, ...

  3. NOIP模拟17.9.21

    NOIP模拟17.9.21 3 58 145 201 161.5 样例输出21.6 数据规模及约定对于40% 的数据,N <= 20对于60% 的数据,N <= 1000对于100% 的数 ...

  4. Leetcode11.Container With Most Water盛最多水的容器

    给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0).找出其中的两条线, ...

  5. Leetcode581.Shortest Unsorted Continuous Subarray最短无序连续子数组

    给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序. 你找到的子数组应是最短的,请输出它的长度. 示例 1: 输入: [2, 6, 4, 8, 1 ...

  6. c++的引用用法

    一.引用简介 引用就是某一变量(目标)的一个别名,对引用的操作与对变量的直接操作完全一样. 引用的声明方法:类别标识符&引用名=目标变量名: 例1: int a; int &ra=a; ...

  7. VMware workstation12安装苹果虚拟机

    一.前言--准备工作 在win10上安装Mac虚拟机,既是费劲又是费内存的活儿 1.安装Vmware 2.下载MacOS的镜像:自行百度下载 3. unlocker的下载地址:http://downl ...

  8. 第十章—DOM(0)—NODE类型

    DOM1定义了一个node接口,该接口由DOM的所有节点类型实现. 所有的节点都存在这样或那样的关系.在HTML中,head,body可以看出是html的子元素,html是head,body的父元素, ...

  9. Linux 7.X 网络配置

    Linux 7.X 网络配置 环境: 笔记本中安装了虚拟机,在虚拟机中安装了Redhat 7.4版本的操作系统,现配置该操作系统网络.(IP.网关等) 相关指令如下: # nmcli connecti ...

  10. objectarx之判断给定的三点是否共线

    bool ThreePointIsCollinear(const AcGePoint2d &pt1, const AcGePoint2d &pt2, const AcGePoint2d ...