洛谷P2279 消防局的设立【树形dp】
题目:https://www.luogu.org/problemnew/show/P2279
题意:一棵树。在节点处建消防站,可以覆盖与他距离在2之内的节点。问最少要建多少个消防站,可以覆盖所有的节点。
思路:有一种贪心的思路,看大部分题解都是这样。
如果要覆盖当前节点(自己不建),那么可能是父亲,兄弟,祖父建了。
但是我们发现,在祖父建覆盖的范围比父亲兄弟要更广一些。所以就贪心的取深度最深的节点,在他的祖父处建一个。
因为想练dp所以没写贪心的。
看结构感觉是树形dp。$dp[i]$表示以$i$为根的子树的情况,想再开一维表示$i$有没有建。后来发现状态好像并不够。
因为只考虑子树的话,当前节点$i$不被覆盖也没关系,他可以被他的父亲或祖先覆盖。
所以大情况分成两种,$i$被覆盖和$i$没被覆盖。
其中$i$被覆盖可以是因为$i$自己建了,也可以是因为有一个儿子建了或者是有一个孙子建了。所以这里有三种状态。
$i$没被覆盖还可以分成只有$i$没被覆盖和$i$和儿子都没有被覆盖。这里又是两种状态。
所以总共是5中状态:
$dp[i][0],在i处建$
$dp[i][1], i处不建但i至少有一个儿子建了$
$dp[i][2],i和儿子都不建但至少有一个孙子建了$
$dp[i][3],自己还没被覆盖,儿子已经被覆盖$
$dp[i][4], 自己和儿子都还没被覆盖$
转移方程:
$dp[i][0] = 1 + \sum min(dp[son][0...4])$每一个儿子的任何一种状态都可以。所以每个儿子都取5种状态的最小的。
$dp[i][1] = min(dp[son1][0] + \sum_(son != son1) min(dp[son][0...3]))$,这里一个巧妙的处理方法是先将每一个儿子的$min(dp[son][0...3])$加上,在找到最小的$dp[son][0]-min(dp[son][0...3])$最后加上。
$dp[i][2] = min(dp[son1][1] + \sum_(son!=son1)(min(dp[son][0...2]))$,此时如果son不在子树被覆盖的话,别的节点也reach不到了。处理方法和上面也一样。
$dp[i][3] = \sum min(dp[son][0...2])$
$dp[i][4] = \sum min(dp[son][0...3]$
#include<cstdio>
#include<cstdlib>
#include<map>
#include<set>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<stack>
#include<queue>
#include<iostream> #define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef pair<int, int> pr; int n;
const int maxn = ;
int fa[maxn];
vector<int>son[maxn];
int dp[maxn][]; void dfs(int rt)
{
if(son[rt].size() == ){
dp[rt][] = ;
dp[rt][] = dp[rt][] = inf;
dp[rt][] = dp[rt][] = ;
return;
}
dp[rt][] = ;
int maxson = inf, maxgs = inf;
for(int i = ; i < son[rt].size(); i++){
dfs(son[rt][i]);
int tmp1 = inf, tmp2 = inf, tmp3 = inf;
for(int j = ; j < ; j++){
tmp1 = min(tmp1, dp[son[rt][i]][j]);
if(j < )tmp2 = min(tmp2, dp[son[rt][i]][j]);
if(j < )tmp3 = min(tmp3, dp[son[rt][i]][j]);
}
dp[rt][] += tmp1;
dp[rt][] += tmp2;
maxson = min(maxson, dp[son[rt][i]][] - tmp2);
maxgs = min(maxgs, dp[son[rt][i]][] - tmp3);
dp[rt][] += tmp3;
dp[rt][] += tmp3;
dp[rt][] += tmp2;
}
dp[rt][] += maxson;
dp[rt][] += maxgs; } int main()
{
scanf("%d", &n);
for(int i = ; i <= n; i++){
scanf("%d", &fa[i]);
son[fa[i]].push_back(i);
}
dfs();
printf("%d\n", min(dp[][], min(dp[][], dp[][]))); }
洛谷P2279 消防局的设立【树形dp】的更多相关文章
- 洛谷P2279消防局的设立
传送门啦 一个很摸不清头脑的树形dp 状态: $ dp[i][0] $ :选自己 $ dp[i][1] $ :选了至少一个儿子 $ dp[i][2] $ :选了至少一个孙子 ------------- ...
- 洛谷P2279 消防局的设立 [HNOI2003] 贪心
正解:贪心 解题报告: 传送门! 这题贪心得挺显然的,,,?居然能有蓝,,,是蓝题太水了嘛,,,? 简单说下,这题一看到就能想到,对最低的没被覆盖到的点给它的祖父建一个消防局 没了? 哦这题实现还挺有 ...
- 洛谷 P3177 [HAOI2015]树上染色 树形DP
洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...
- P2279 [HNOI2003]消防局的设立[树形dp]
题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...
- 洛谷P1040 加分二叉树(树形dp)
加分二叉树 时间限制: 1 Sec 内存限制: 125 MB提交: 11 解决: 7 题目描述 设一个n个节点的二叉树tree的中序遍历为(l,2,3,...,n),其中数字1,2,3,...,n ...
- 洛谷P4438 道路 [HNOI/AHOI2018] 树形dp
正解:树形dp 解题报告: 传送门! 昂首先看懂题目趴QwQ大概就是说有棵满二叉树,有n个叶子节点(乡村)和n-1个非叶子节点,然后这棵树的每个节点有三个属性abc,对每个非叶子节点可以从与子节点的两 ...
- 洛谷 P4201 设计路线 [NOI2008] 树形dp
正解:树形dp 解题报告: 大概是第一道NOI的题目?有点激动嘻嘻 然后先放个传送门 先大概港下这题的题意是啥qwq 大概就是给一棵树,然后可以选若干条链把链上的所有边的边权变成0,但是这些链不能有交 ...
- 【BZOJ1217】[HNOI2003]消防局的设立 树形DP
[BZOJ1217][HNOI2003]消防局的设立 Description 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地, ...
- 洛谷 P3267 [JLOI2016/SHOI2016]侦察守卫(树形dp)
题面 luogu 题解 树形\(dp\) \(f[x][y]表示x的y层以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价.\) \(g[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上 ...
随机推荐
- ruby tk实现简易计算器
#encding:GBK require 'tk' module Const WIDTH_OF_PANEL = 370 HEIGHT_OF_PANEL = 520 SIZE_OF_BUTTON_H = ...
- Windows注册表中修改UAC(用户账号控制)及批处理脚本
注册表路径: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows/CurrentVersion/Policies/System 键说明: ConsentProm ...
- LIUNX随堂学习-3 权限
1.权限分为三类:读r,写w,执行x 2.读r:可以ls改目录下的子文件名,子目录名 写w:可以在该目录下创建.删除.重命名 执行x:可以cd到该目录下 3. ll (ls -l) 下详细信息的意义 ...
- Intercity Travelling CodeForces - 1009E (组合计数)
大意: 有一段$n$千米的路, 每一次走$1$千米, 每走完一次可以休息一次, 每连续走$x$次, 消耗$a[1]+...+a[x]$的能量. 休息随机, 求消耗能量的期望$\times 2^{n-1 ...
- 怎样解决Chrome浏览器因为禁止音频自动播放所造成的视频无法自动播放且报错: Uncaught (in promise) DOMException的问题
这个问题是谷歌基于用户体验方面的考虑, 对页面加载时自动播放的音频作了限制, 试想一下, 如果你打开某个页面就立刻自动播放某种不可描述的声音, 那体验想必是十分酸爽. 尽管这个设定是针对音频的, 但实 ...
- (七)Activiti之历史活动查询和历史任务查询和流程状态查询
一.历史活动查询 本章案例是基于上一章节案例的基础上,流程走完后进行测试的,也就是下图的流程从学生请假到班主任审批都已经完成,本章用来测试查询历史活动和历史任务的 activiti5的历史活动包括所有 ...
- 关于__new__和__init__
关于__new__和__init__ 例如一个类 class Foo(object): def __init__(self): print(1) def __new__(self): print(2) ...
- centos安装mysql(for 小白)
安装前提: 安装号centos.SecureCRT 安装准备: centos自带数据库Mariadb,先将其移除 下载mysql: 镜像网址:http://mirrors.sohu.com/mysql ...
- JS错误信息类型
1.SyntaxError 语法错误 ①变量名不规范 // 变量名不规范 var 1 = 1; 未被捕获的语法错误,这个错误是js机制自动抛出来的 意外的数字 // 下面两个是同一种情况 var 1a ...
- 一款结合nmap及mascan还有shodan的扫描脚本
github在这里 https://github.com/s0md3v/Silver 很是舒服 Usage Note: Silver scans all TCP ports by default i. ...