题目描述

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

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

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

解析

这道题似乎可以贪心,但是窝是为了dp而来的,显然这是个树形dp。

定义状态:

\(dp[0][x]\)表示消防局已经覆盖了以\(x\)为根节点的子树和该节点的父节点和爷爷节点,可以看作该点有消防局;

\(dp[1][x]\)表示已经至少覆盖了以\(x\)为根节点的子树和该节点的父节点,可以看作该点的儿子有消防局;

\(dp[2][x]\)表示已经至少覆盖的以\(x\)为根节点的子树,可以看作该点的孙子节点有消防局;

\(dp[3][x]\)表示已经至少覆盖了所有以\(x\)的儿子为根节点的子树;

\(dp[4][x]\)表示已经至少覆盖了所有以\(x\)的孙子为根节点的子树,后面这俩都是用来给上面状态的转移作中介的。

务必明确一点:实际上对于某个状态,我们刻画其为以某点为根的子树子树与父节点、爷爷节点都被覆盖,并且子树包含根节点。

对于状态\(dp[0][x]\),显然在\(x\)节点就必须有一个消防局,才能满足状态定义。假设其儿子节点的集合为\(t\),且有\(y\in t\),为了使得答案最优,我们直接从\(dp[4][y]\)转移过来。

也就是:\(dp[0][x]=1+\sum_{y \in t}dp[4][y]\)

对于状态\(dp[1][x]\),显然在\(x\)的某个儿子节点上必须要有一个消防局,即\(dp[0][y]\),此时其它儿子节点都没有被覆盖时最优的,即\(dp[3][y]\)。由于状态\(dp[0][x]\)包含了这个状态,于是我们把它也加进来取\(\min\)。

沿用上面的假设,我们得到:\(dp[1][x]=\min\limits_{y\in t,z\in t且z\ne y}\{dp[0][y]+\sum dp[3][z],dp[0][x]\}\)

对于状态\(dp[2][x]\),与二相似,在\(x\)的某个孙子节点上必须要有一个消防局,即\(dp[1][y]\),此时其它儿子节点都恰好为状态\(dp[2][y]\)时为最优解。由于状态\(dp[0/1][x]\)都包含了这个状态,于是我们把它们也加进来取\(\min\)。

沿用上面的假设,我们得到:\(dp[2][x]=\min\limits_{y\in t,z\in t且z\ne y}\{dp[1][y]+\sum{dp[2][z]},dp[0/1][x]\}\)

对于状态\(dp[3][x]\),我们直接像\(dp[0][x]\)一样,加上所有\(dp[2][y]\)就行。然后类比上面三条,同理,\(dp[0/1/2][x]\)显然包含该状态。

沿用上面的假设,我们得到:\(dp[3][x]=\min\limits_{y\in t}\{\sum dp[2][y],dp[0/1/2][x]\}\)

同上。

注意:叶子节点和叶子节点的父节点,它们的\(dp[1][x],dp[2][x]\)状态必须有一个消防局,否则不满足状态定义,因此初始化的时候要稍微注意一下。


这道题就变得简单了。

参考代码

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<ctime>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#define N 1010
#define INF 0x7fffffff
using namespace std;
struct node{
int next,ver;
}g[N<<1];
int tot,head[N],n;
int dp[5][N];
inline void add(int x,int y)
{
g[++tot].ver=y;
g[tot].next=head[x],head[x]=tot;
}
inline void dfs(int x)
{
dp[0][x]=1;dp[3][x]=0;dp[4][x]=0;
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
dfs(y);
dp[0][x]+=dp[4][y];
dp[3][x]+=dp[2][y];
dp[4][x]+=dp[3][y];
}
if(head[x]==0){
dp[1][x]=dp[2][x]=1;
}
else{
dp[1][x]=dp[2][x]=INF;
for(int i=head[x];i;i=g[i].next){
int y=g[i].ver;
int t1=dp[0][y],t2=dp[1][y];
for(int j=head[x];j;j=g[j].next){
if(i==j) continue;
int z=g[j].ver;
t1+=dp[3][z];
t2+=dp[2][z];
}
dp[1][x]=min(dp[1][x],t1);
dp[2][x]=min(dp[2][x],t2);
}
}
for(int i=1;i<=4;++i)
dp[i][x]=min(dp[i][x],dp[i-1][x]);
}
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;++i){
int u;
scanf("%d",&u);
add(u,i);
}
dfs(1);
cout<<dp[2][1]<<endl;
return 0;
}

P2279 [HNOI2003]消防局的设立[树形dp]的更多相关文章

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

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

  2. [HNOI2003]消防局的设立 树形dp // 贪心

    https://www.luogu.org/problemnew/show/P2279 一开始就想到了贪心的方法,不过一直觉得不能证明. 贪心的考虑是在深度从深到浅遍历每个结点的过程中,对于每个没有覆 ...

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

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

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

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

  5. [HNOI2003] 消防局的设立 - 树形dp

    仍然是点覆盖集问题,但覆盖半径变成了\(2\) 延续上一题的思路,只是式子更加复杂了 想体验一下min_element大法于是不想优化了 #include <bits/stdc++.h> ...

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

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

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

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

  8. P2279 [HNOI2003]消防局的设立 贪心or树形dp

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

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

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

随机推荐

  1. 存储Flash--NOR flash和 Nand flash

    flash是存储芯片的一种,通过特定的程序可以修改里面的数据.FLASH在电子以及半导体领域内往往表示Flash Memory的意思,即平时所说的“闪存”,全名叫Flash EEPROM Memory ...

  2. junit单元测试不通过报documentationPluginsBootstrapper相关异常

    这是因为Spring整合springfox-swagger2后导致的,错误信息如下: -- ::, [main] [WARN] [org.springframework.context.support ...

  3. Mongodb CPU占用率达90%的优化调整报告

    1问题描述 1.1现场的数据库部署情况 服务器基本情况如下: CPU 20逻辑核,40线程 内存 64 G 硬盘 D盘 :1T SSD E盘:3T SATA F盘:3T SATA 在这台机器上同时部署 ...

  4. php_mvc实现步骤五

    5.match_controller 控制器层典型实现 控制器类 依据功能的相关性,将一系列相关的功能,使用一个控制器类来处理,而该控制器的每个方法,就对因某个功能. 注意:控制器是按照功能划分的.( ...

  5. 在ensp上的mstp基础配置

    为什么需要mstp? 因为stp中存在阻塞端口,阻塞后不承载流量,造成了带宽浪费 实验模拟 实验拓扑 相关参数 首先我们在交换机上创建vlan 10,20 设置端口 默认是运行mstp服务看一下

  6. Django实现博客项目

    一.项目概述 项目运行环境 Python3.6+ Django 1.11 MySQL 5.7 其他插件(图片处理.分页.验证码....) 项目详细功能介绍 前台功能 项目首页展示 轮播图 博客推荐 最 ...

  7. LeetCode 686. 重复叠加字符串匹配(Repeated String Match)

    686. 重复叠加字符串匹配 686. Repeated String Match 题目描述 给定两个字符串 A 和 B,寻找重复叠加字符串 A 的最小次数,使得字符串 B 成为叠加后的字符串 A 的 ...

  8. Callable+Future

    Future提供了三种功能: 1)判断任务是否完成: 2)能够中断任务: 3)能够获取任务执行结果 package com.moreas; import java.util.concurrent.Ca ...

  9. Java开发笔记(一百三十)Swing的选择框

    不管是AWT还是Swing,都把选择框分成两类:复选框和单选按钮,这两类控件无论是外观上还是功能上均有显著差异.例如,在外观方面,复选框是在方框内打勾,而单选按钮是在圆圈内画圆点:在功能方面,复选框允 ...

  10. Appium移动端测试--搭建测试环境

    目录 文章目录如下 安装Android Studio及Android SDK 更改VDM默认存储路径 通过npm安装Appium Server 启动Appium GUI模式 Appium连接会话 Ap ...