题目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】的更多相关文章

  1. 洛谷P2279消防局的设立

    传送门啦 一个很摸不清头脑的树形dp 状态: $ dp[i][0] $ :选自己 $ dp[i][1] $ :选了至少一个儿子 $ dp[i][2] $ :选了至少一个孙子 ------------- ...

  2. 洛谷P2279 消防局的设立 [HNOI2003] 贪心

    正解:贪心 解题报告: 传送门! 这题贪心得挺显然的,,,?居然能有蓝,,,是蓝题太水了嘛,,,? 简单说下,这题一看到就能想到,对最低的没被覆盖到的点给它的祖父建一个消防局 没了? 哦这题实现还挺有 ...

  3. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

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

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

  5. 洛谷P1040 加分二叉树(树形dp)

    加分二叉树 时间限制: 1 Sec  内存限制: 125 MB提交: 11  解决: 7 题目描述 设一个n个节点的二叉树tree的中序遍历为(l,2,3,...,n),其中数字1,2,3,...,n ...

  6. 洛谷P4438 道路 [HNOI/AHOI2018] 树形dp

    正解:树形dp 解题报告: 传送门! 昂首先看懂题目趴QwQ大概就是说有棵满二叉树,有n个叶子节点(乡村)和n-1个非叶子节点,然后这棵树的每个节点有三个属性abc,对每个非叶子节点可以从与子节点的两 ...

  7. 洛谷 P4201 设计路线 [NOI2008] 树形dp

    正解:树形dp 解题报告: 大概是第一道NOI的题目?有点激动嘻嘻 然后先放个传送门 先大概港下这题的题意是啥qwq 大概就是给一棵树,然后可以选若干条链把链上的所有边的边权变成0,但是这些链不能有交 ...

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

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

  9. 洛谷 P3267 [JLOI2016/SHOI2016]侦察守卫(树形dp)

    题面 luogu 题解 树形\(dp\) \(f[x][y]表示x的y层以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价.\) \(g[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上 ...

随机推荐

  1. Z1. 广度优先搜索(BFS)解题思路

    /** BFS 解题思路 特点:从某些特定的节点开始,感染相邻的节点; 被感染的节点,再感染其相邻的节点,以此类推. 题目常见于数据结构包括 二维数组.树.图 **/ /** 1). 二维数组特定节点 ...

  2. 基于laravel框架构建最小内容管理系统

    校园失物招领平台开发 --基于laravel框架构建最小内容管理系统 摘要 ​ 针对目前大学校园人口密度大.人群活动频繁.师生学习生活等物品容易遗失的基本现状,在分析传统失物招领过程中的工作效率低下. ...

  3. Python+Appium启动手机APP或者浏览器

    一.设备信息配置 脚本如下: from appium import webdriver class my_app(): def __init__(self): desired_caps = {} # ...

  4. Zuma CodeForces - 607B (区间DP)

    大意: 给定字符串, 每次删除一个回文子串, 求最少多少次删完. #include <iostream> #include <cstdio> #define REP(i,a,n ...

  5. 关于MySQL的驱动org.gjt.mm.mysql.Driver

    今天看了一个比较老视频使用org.gjt.mm.mysql.Driver来驱动连接,便试了一下看看怎么样,结果一直连不上数据库,后来看了tomcat的后台发现有报这个问题,于是把驱动改成com.mys ...

  6. jacascript 基础数据类型(一)

    前言:这是笔者学习之后自己的理解与整理.如果有错误或者疑问的地方,请大家指正,我会持续更新! 数据类型有 number.boolean.string.object.null.undefined; un ...

  7. (九)springmvc之json的处理(服务端发送json数据到客户端)

    一.json处理方法有两种 1:导入Spring需要json的jar包.(本例使用) 使用@ResponseBody该注解用于将Controller的方法返回的对象,通过HttpMessageConv ...

  8. GDB数据库SQL操作平台

    GDB数据库SQL操作平台 开发本软件的初衷:由于计算数据库要素层属性的时候,涉及到要计算多个字段,或者要根据代码计算名称,得一个一个的筛选并计算,过程比较繁琐,于是就想能不能通过像处理SQLServ ...

  9. SQL递归查询(with as)

    SQL递归查询(with cte as) with cte as(    select Id,Pid,DeptName,0 as lvl from Department    where Id = 2 ...

  10. C++ 容器一图以蔽之

    读完C++ primary 容器相关章节,有必要总结一下容器的要点,一图说明. 其中的问题,以下是我的一些想法,欢迎交流. 问题1. STL源码剖析 · vector 问题2. STL源码剖析 · R ...