博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[HNOI 2003] 消防局的设立
阅读量:4971 次
发布时间:2019-06-12

本文共 2729 字,大约阅读时间需要 9 分钟。

洛谷 2279 03 湖南 消防局的设立

本题地址:

题目描述

2020 年,人类在火星上建立了一个庞大的基地群,总共有 n 个基地。起初为了节约材料,人类只修建了 n-1 条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。如果基地 A 到基地 B 至少要经过 d 条道路的话,我们称基地 A 到基地 B 的距离为 d。
由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过 2 的基地的火灾。
你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。
输入输出格式
输入格式:
输入文件名为 input.txt。
输入文件的第一行为 n (n<=1000),表示火星上基地的数目。接下来的 n-1 行每行有一个正整数,其中文件第 i 行的正整数为 a[i],表示从编号为 i 的基地到编号为 a[i] 的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有 a[i]<i

输出格式:

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

输入输出样例

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


思路

很有意思的一道(shui)题,但是对于某蒟蒻来说,也是想了很久。。。T_T

树形 dp,就是 dfs+ 向上更新。比较难想到的是状态,这里每种节点用了 5 个 dp[v][0~4],分别代表某个节点 v** 至少覆盖到孙子、儿子、自己、父亲、祖父节点 ** 所需的消防站个数。

然后是状态转移。从覆盖到祖父开始,很容易看出来,这个节点 v 自己一定要涂色(设消防局),向上两个距离,向下两个距离,所以 v 的儿子们只要管到各自的孙子就行了。画张图理解下:

这是图

如果要求覆盖到父亲,那么一种情况就是同上,因为这 5 种状态是包含的关系,而不是排斥的。第二种情况,就是 v 的某个儿子覆盖到它的祖父(一起唱:儿子的爷爷是爸爸),由于那个儿子可以向上两个距离,同时也可以绕下来覆盖 v 的其他的儿子节点,从而 v 的其他儿子只要管到各自的儿子就行了。

如果要求覆盖到自己,第一种情况也包含在上面。第二种情况,v 的某个儿子覆盖到 v(就是他的父亲),其余的儿子管到自身。

之后的以此类推←_←具体见代码

代码

#include 
#include
#include
using namespace std;const int MAXN = 3000, INF = 0x3f3f3f3f;int head[MAXN], next[MAXN], to[MAXN], pa[MAXN], tot, N;bool lf[MAXN]; //是否为叶子节点 int dp[MAXN][10]; //树状dp//dp[v][n] = 从n=0时为v的孙子节点,到n=4时为v的祖父节点,覆盖到第n层所需的最少数目void init(){ memset(head, -1, sizeof(head)); tot = 0;}void add2(int a, int b){ to[tot] = b; next[tot] = head[a]; head[a] = tot++; to[tot] = a; next[tot] = head[b]; head[b] = tot++;}void pushup(int v){ //将v的子节点的信息更新到v dp[v][4] = 1; int min1 = INF, min2 = INF; for(int i = head[v]; ~i; i = next[i]){ int u = to[i]; if(u != pa[v]){ dp[v][4] += dp[u][0];// dp[v][3] += dp[u][1];// dp[v][2] += dp[u][2]; dp[v][1] += dp[u][2]; dp[v][0] += dp[u][1]; min1 = min(min1, dp[u][4] - dp[u][1]); min2 = min(min2, dp[u][3] - dp[u][2]); } } dp[v][3] = dp[v][0] + min1; dp[v][2] = dp[v][1] + min2; for(int i = 3; i >= 0; --i){ dp[v][i] = min(dp[v][i], dp[v][i+1]); }}void dfs(int v){ if(lf[v]){ dp[v][4] = dp[v][3] = dp[v][2] = 1; return; } for(int i = head[v]; ~i; i = next[i]){ int u = to[i]; if(u != pa[v]){ dfs(u); } } pushup(v); }int main(){ freopen("in.txt", "r", stdin); scanf("%d", &N); if(N == 0){ printf("0\n"); return 0; } init(); for(int i = 2; i <= N; ++i){ int p; scanf("%d", &p); pa[i] = p; lf[p] = false; add2(i, p); } dfs(1); printf("%d\n", dp[1][2]); return 0;}

转载于:https://www.cnblogs.com/will7101/p/6506688.html

你可能感兴趣的文章
线段树(已修改+补题
查看>>
第一百一十七天 how can I 坚持
查看>>
10年ACL,A Unified Graph Model for Sentence-based Opinion Retrieval
查看>>
JavaAgent入门
查看>>
50个 css 生成器
查看>>
fremarker
查看>>
firdac支持的序列和还原格式
查看>>
Linxu磁盘分区
查看>>
asp.net C# 题目大全
查看>>
Java加密技术(一)—— HMACSHA1 加密算法
查看>>
HDU 4349
查看>>
System.Diagnostics.Debug.WriteLine 在OutPut中无输出
查看>>
B-JUI学习
查看>>
D -- POJ 1363 Rails
查看>>
最大公约数
查看>>
在 CentOS 7上安装并配置 Python 3.6 环境
查看>>
linux dns 工具包 -- bind-utils
查看>>
29.奖金(拓扑排序)
查看>>
jenkins之构建触发器
查看>>
Spring Boot配置文件详解-ConfigurationProperties和Value优缺点-(转)好文
查看>>