[Luogu2279][HNOI2003] 消防局的设立

文章目录

    • 题目
  • 法一:树上DP
    • 思路
    • 代码实现
  • 法二:贪心 + 搜索
    • 思路
    • 代码实现

在这里插入图片描述

题目

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

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

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

输入格式
输入文件的第一行为n (n<=1000),表示火星上基地的数目。接下来的n-1行每行有一个正整数,其中文件第i行的正整数为a[i],表示从编号为i的基地到编号为a[i]的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有a[i]<i。
输出格式
输出文件仅有一个正整数,表示至少要设立多少个消防局才有能力及时扑灭任何基地发生的火灾。

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

法一:树上DP

思路

这个可是重头戏,让我抓狂了整整一晚呢!!!
在这里插入图片描述
先给出DP[i][j]DP[i][j]DP[i][j]的含义:
表示距离树上的i点最近的一个消防站的距离为j的所建的消防站的个数

那么我们就可以get到以下DP含义(下面要用,一定要理解哦~~)

DP[i][0]:把离i最近的消防站就直接设在i节点上DP[i][0]:把离i最近的消防站就直接设在i节点上DP[i][0]ii
DP[i][1]:把离i最近的消防站设在i的某一个儿子节点vDP[i][1]:把离i最近的消防站设在i的某一个儿子节点vDP[i][1]iiv
DP[i][2]:把消防站设在i的某一个孙子节点vDP[i][2]:把消防站设在i的某一个孙子节点vDP[i][2]iv
DP[i][3]:把消防站设在i的某一个儿子节点v的某一个孙子节点DP[i][3]:把消防站设在i的某一个儿子节点v的某一个孙子节点DP[i][3]iv
DP[i][4]:把消防站设在i的某一个孙子节点v的某一个孙子节点DP[i][4]:把消防站设在i的某一个孙子节点v的某一个孙子节点DP[i][4]iv

接下来还应该明白这样一个DP式,假设v是u的一个儿子节点
DP[u][i]=DP[v][i−1]DP[u][i]=DP[v][i-1]DP[u][i]=DP[v][i1]
解释:距离u的距离为i,那么距离u的儿子v的距离就-1了


接下来就要推DP式了,上图分析理解
在这里插入图片描述
(虽然给的是很简单的单链,必要时要幻想每一个v都有兄弟,他们并不孤单)
在这里插入图片描述
我们就只站在root往深处儿子看,不用管祖先,
因为这些都会在回溯的时候在祖先那一层进行处理


①:把消防站建在root处
看图可以知道,v1,v2两层会被root覆盖,
这个时候我们就要对于root的每一个子树内部进行处理,
因为其它子树再往深了建就更不可能覆盖到其他子树的点了,
所以DP[i][0]+=DP[v][4]DP[i][0]+=DP[v][4]DP[i][0]+=DP[v][4]

解释:看图?v3, v4,v5…等深的节点都没有被覆盖,这里就要用到贪心的思想
我把消防站建在v5肯定要优于v3,v4因为v5可以再往下多覆盖两层
其实应该加上DP[i][5]DP[i][5]DP[i][5]因为v5距离root的距离是5,
上面就已经铺垫了DP[i][5]=DP[v][4]DP[i][5]=DP[v][4]DP[i][5]=DP[v][4]


②:把消防站建在v3处
那么v3可以覆盖v1,v2,v4,v5
所以对于DP[i][3]+=DP[v][2]DP[i][3]+=DP[v][2]DP[i][3]+=DP[v][2]
可是root没有被覆盖啊???
在这里插入图片描述
不急,这个root不是非要现在处理不行,
root可以被丢给它的爷爷覆盖,等到回溯的时候,它就变成了爷爷的v2,也会被覆盖


③:把消防站建在v4处
那么与②差不多
DP[i][4]+=DP[v][3]DP[i][4]+=DP[v][3]DP[i][4]+=DP[v][3]
我们把root和root的儿子v1那一层都丢给root的父亲去覆盖,


接下来的两种情况就稍微有点复杂了,
④:把消防站建在v1处
可以知道v1可以通过V形蛇皮操作覆盖了root的其它儿子以及root
那么对于其它的子树而言,应该建在它们的v4那一层,
因为它们没有必要去覆盖v1那一层的所有节点
所以我们要找到最小的一个v1节点,然后对于root的其它子节点找v4那一层
⑤:把消防站建在v2处


与④雷同的
可以知道v2可以通过I形蛇皮操作覆盖了root以及v2那一条单链的v1节点
那么对于其它的子树而言,应该建在它们的v3那一层,
因为它们必须要内部消化去覆盖它们的v1节点,就不用管root
所以我们要找到最小的一个v2节点,然后对于root的其它子节点找v5那一层


对于④⑤的DP处理,在这里讲一下,分析出来要求最小值
在这里插入图片描述
但是其实没有必要去双重循环找,因为我们发现就是求一个
④:DP[v][0]DP[v][0]DP[v][0]和其他所有DP[v′][3]DP[v'][3]DP[v][3]的最小值
⑤:DP[v][1]DP[v][1]DP[v][1]和其他所有DP[v′][2]DP[v'][2]DP[v][2]的最小值
DP[v][0]DP[v][0]DP[v][0]肯定大于DP[v′][3]DP[v'][3]DP[v][3]DP[v][1]DP[v][1]DP[v][1]肯定大于DP[v′][2]DP[v'][2]DP[v][2]
所以就是求一个DP[v][0]DP[v][0]DP[v][0]DP[v][3]DP[v][3]DP[v][3]的最小值,DP[v][1]DP[v][1]DP[v][1]DP[v][2]DP[v][2]DP[v][2]的最小值
O(n)O(n)O(n)就可以进行更新
在这里插入图片描述

代码实现

#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 1005
vector < int > G[MAXN];
int n, result = 0x7f7f7f7f;
int f[MAXN];
int dp[MAXN][5];void dfs ( int u ) {dp[u][0] = 1;for ( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if ( v == f[u] ) continue;dfs ( v );dp[u][0] += dp[v][4];dp[u][3] += dp[v][2];dp[u][4] += dp[v][3];}if ( G[u].size() == 1 && u != 1 )dp[u][1] = dp[u][2] = 1;else {int f1 = 0x7f7f7f7f, f2 = 0x7f7f7f7f;for ( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if ( v == f[u] ) continue;f1 = min ( f1, dp[v][0] - dp[v][3] );f2 = min ( f2, dp[v][1] - dp[v][2] );dp[u][1] += dp[v][3];dp[u][2] += dp[v][2];}dp[u][1] += f1;dp[u][2] += f2;}for ( int i = 1;i <= 4;i ++ )dp[u][i] = min ( dp[u][i], dp[u][i - 1] );
}int main () {scanf ( "%d", &n );for ( int i = 2;i <= n;i ++ ) {scanf ( "%d", &f[i] );G[f[i]].push_back( i );G[i].push_back( f[i] );}dfs ( 1 );printf ( "%d", dp[1][2] );return 0;
}

法二:贪心 + 搜索

思路

我写这篇文章的重点就是解释法一,所以这个贪心我就不会像以前一样,细讲了
反正也很简单,连我这种蒟蒻都一次在这里插入图片描述


首先我们考虑一条单链的状态,那么我们肯定都想把消防站建在中间,这样它就可以往上灭两层在这里插入图片描述再往下灭两层在这里插入图片描述
这样肯定是最优的


在这里贪心思想就出现了,我们找到一个当前深度最深的点,
去找这个点的祖先的祖先–他的爷爷fa
这样的话,fa不仅能把当前点覆盖,还可以覆盖fa的所有儿子,以至于fa的所有兄弟,
甚至于fa的父亲和爷爷


至于怎么覆盖这些点,我们可以用bfs以fa为中心去扩散半径为2的所有点
不用担心会很多,可以证明每个点最多被访问3次
一次是它作为中心,去扩散
一次是它作为中转点,即半径为1再去扩散一层
一次是它作为边缘点,即半径为2停止扩散


是不是这个贪心很简单在这里插入图片描述
在这里插入图片描述

代码实现

#include <queue>
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
#define MAXN 1005
struct node {int u, step;node () {}node ( int U, int STEP ) {u = U;step = STEP;}
};
struct noded {int dep, id;
}tree[MAXN];
queue < node > q;
vector < int > G[MAXN];
int n, result;
int f[MAXN];
bool vis[MAXN];bool cmp ( noded x, noded y ) {return x.dep > y.dep;
}void dfs ( int u, int depth ) {tree[u].dep = depth;tree[u].id = u;for ( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if ( v == f[u] ) continue;dfs ( v, depth + 1 );}
}void bfs ( int root ) {vis[root] = 1;q.push ( node ( root, 0 ) );while ( ! q.empty() ) {node t = q.front();q.pop();if ( t.step == 2 ) continue;for ( int i = 0;i < G[t.u].size();i ++ ) {int v = G[t.u][i];if ( ! vis[v] )vis[v] = 1;q.push( node ( v, t.step + 1 ) );}}
}void solve () {for ( int i = 1;i <= n;i ++ ) {if ( ! vis[tree[i].id] ) {result ++;int fa = f[f[tree[i].id]];if ( fa == 0 ) fa = 1;bfs ( fa );}}
}int main() {scanf ( "%d", &n );for ( int i = 2;i <= n;i ++ ) {scanf ( "%d", &f[i] );G[f[i]].push_back( i );G[i].push_back( f[i] );}dfs ( 1, 1 );sort ( tree + 1, tree + n + 1, cmp );solve ();printf ( "%d", result );return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/318248.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

8.13模拟:分治二分倍增快速幂

文章目录前言考场复盘T1 roadT2 shopT3 runT4 stairs总结前言 240分 100802040 T3少取了一个模结果全挂掉了&#xff08;好不容易推出来了…&#xff09; T2也因为各种奇怪的错误挂了分 qwq 吸取教训吧 考场 今天先看题 T1第一眼看错了题意觉得水的不行 T3YBT原题且很水 T2T…

dnSpy 强大的.Net反编译软件

一说起.net的反编译软件&#xff0c;大家首先想到的就是Reflector&#xff0c;ILSpy&#xff0c;dotPeek等等。而dnSpy同样是一款优秀的反编译软件&#xff0c;同时它是开源免费的。官方的描述是: dnSpy是一个调试器和.NET组件编辑器。 即使您没有任何可用的源代码&#xff0c;…

图的匹配

定义见&#xff1a;OI-Wiki 图的匹配 。 二分图 解法 \(1\) &#xff1a;网络流(通用) 二分图最大匹配可以转换成最大流(费用流)模型 。 如果使用 \(\operatorname{Dinic}\) 算法求该网络的最大流&#xff0c;复杂度\(O(\sqrt{n}m)\) 。 具体代码见博客文章网络流 。 解法 \(2\…

AT2161-[ARC065D]シャッフル/Shuffling【dp】

正题 题目链接:https://www.luogu.com.cn/problem/AT2161 题目大意 长度为nnn的0/10/10/1串&#xff0c;mmm个区间&#xff0c;你可以按照顺序任意排列区间中的数字&#xff0c;求最后的可能情况数。 保证给出区间的左端点不降。 1≤n,m≤30001\leq n,m\leq 30001≤n,m≤3000…

【acwing210 异或运算】

【acwing210 异或运算】 题意&#xff1a; 给定你由N个整数构成的整数序列&#xff0c;你可以从中选取一些&#xff08;甚至一个&#xff09;进行异或&#xff08;XOR&#xff09;运算&#xff0c;问所有能得到的不同的结果中第k小的结果是多少。 题解&#xff1a; 把所有数…

小奇探险

文章目录题目题解代码实现题目 小奇去遗迹探险&#xff0c;遗迹里有N个宝箱&#xff0c;有的装满了珠宝&#xff0c;有的装着废品。 小奇有地图&#xff0c;所以它知道每一个宝箱的价值&#xff0c;但是它不喜欢走回头路&#xff0c;所以要按顺序拿这N个宝箱中的若干个。 拿宝…

8.14 模拟:字符串

文章目录前言收获考场复盘T1 wordlistT2 passwordT3 readtreeT4 bracket总结前言 290分 2010070100 又被KH爆碾了qwq T1签到题脑抽写挂了80分… &#xff08;就差这80啊…&#xff09;、 收获 学会了启发式合并 还有一个把字符串所有后缀放进trie树的比较字符串的技巧 考场…

基于Asp.Net Core打造轻量级内部服务治理RPC(二 远程服务设计)

紧接上一篇《基于Asp.Net Core打造轻量级内部服务治理RPC(一)》文章。本文主要讲解基于Asp.Net Core的远程服务设计和实现。在上一篇中讲过,服务提供者提供的服务实际上就是一个Controller&#xff0c;那么是否在该程序中&#xff0c;服务都按照Asp.Net Core 中的Web Api的方式…

[TJOI2008]彩灯

题目&#xff1a; Peter 女朋友的生日快到了&#xff0c;他亲自设计了一组彩灯&#xff0c;想给女朋友一个惊喜。已知一组彩灯是由一排 N个独立的灯泡构成的&#xff0c;并且有 MM 个开关控制它们。从数学的角度看&#xff0c;这一排彩灯的任何一个彩灯只有亮与不亮两个状态&a…

51nod1229-序列求和V2【数学,拉格朗日插值】

正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId1229 题目大意 给出n,k,rn,k,rn,k,r求 ∑i1nikri\sum_{i1}^ni^kr^ii1∑n​ikri 1≤T≤20,1≤n,r≤1018,1≤k≤20001\leq T\leq 20,1\leq n,r\leq 10^{18},1\leq k\leq 20001≤T≤20,1≤n,r≤1018,1≤k≤…

【做题记录】图论杂题

P1268 树的重量 $\texttt{solution}$ 算法&#xff1a;(贪心)\(\) 找规律 当 \(n2\) 时&#xff0c;显然答案就是 \(dis(1,2)\) 。 当 \(n3\) 时&#xff0c;答案&#xff1a; \[\dfrac{dis(1,3)dis(2,3)-dis(1,2)}{2} \]当 \(n\) 是任意的&#xff0c;第 \(n\) 条路径可以处于…

[NOIP 2009 提高组]最优贸易

勤劳的一更题目题解代码实现题目 C国有 n个大城市和 m 条道路&#xff0c;每条道路连接这n个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这 m 条道路中有一部分为单向通行的道路&#xff0c;一部分为双向通行的道路&#xff0c;双向通行的道路在统计条数…

8.15模拟:图论

文章目录前言收获考场复盘T1 recoverT2 teamT3 planT4 seqpath总结至暗时刻 前言 60分 303000 … 已经不是被KH爆碾的问题 &#xff08;KH屹立不倒%%%&#xff09; 昨天祈祷不要挂80了 结果今天挂了160&#xff08;还不算那个背包的70&#xff09; qwq 加油吧 奇怪的教训又增加…

Azure Service Fabric Mesh:一个构建任务关键型微服务的平台

本文要点Azure Service Fabric Mesh&#xff08;目前处于预览阶段&#xff09;是一个完全托管的服务&#xff0c;它使你可以使用“无服务器”方法构建、部署和管理由运行在容器中的多语言服务组成的应用程序。Azure Service Fabric Mesh 通过使用 Envoy Proxy 构建的软件定义网…

【做题记录】人类智慧

CF741C Arpa’s overnight party and Mehrdad’s silent entering 描述&#xff1a;有 \(2n\) 个人坐在一张圆桌&#xff0c;第 \(1\) 个位置与第 \(n\) 个位置相邻。现在给他们分配 \(1\) 或 \(2\) 两种食物。要求任意相邻的三个人食物不完全相同。求是否有可行的分配方案。 转…

CF1039D-You Are Given a Tree【根号分治,贪心】

正题 题目链接:https://www.luogu.com.cn/problem/CF1039D 题目大意 给出nnn个点的一棵树&#xff0c;然后对于k∈[1,n]k\in[1,n]k∈[1,n]求每次使用一条长度为kkk的链覆盖树并且不能重复覆盖点时最大覆盖条数。 1≤n≤1051\leq n\leq 10^51≤n≤105 解题思路 先考虑暴力怎么…

P3265 [JLOI2015]装备购买

题目描述&#xff1a; 给N个整数向量&#xff0c;每个向量带权值&#xff0c;求权值和最小的线性基 题解&#xff1a; 按权值v从小->大排序&#xff0c;依次插入线性基。整数线性基的思想类似&#xff0c;只是此时“消去”不能直接xor完成&#xff0c;需要类似高斯消元一样…

模板:欧拉路

文章目录前言代码前言 就是欧拉路的板子 理解起来有亿点困难&#xff08;连大神学长都还没有完全理解…&#xff09; 不过背起来还是很好背的 请勿模仿 如果是无向图&#xff1a;开一个vis数组&#xff0c;走一条边时把它的反向边标记上即可 代码 #include<bits/stdc.h&g…

Surging1.0发布在即,.NET开发者们,你们还在等什么?

开源&#xff0c;是近三十年来互联网经久不衰的话题。它不仅仅是一种技术分享的形态&#xff0c;更是一种开放&#xff0c;包容&#xff0c;互利共赢的互联网精神。 不到30年前&#xff0c;大神林纳德托瓦兹&#xff0c;在赫尔辛基大学实验室里&#xff0c;开发出了第一个版本的…

[SDOI2016]排列计数 (错排数概念 + 递推公式【附带证明】)

辛勤二更题目题解错排数概念错排数递推公式及其证明代码实现这种题做的时候&#xff1a; 做完后&#xff1a;正常这就是生活&#xff0c;我们要学会习惯 题目 求有多少种长度为 n 的序列 A&#xff0c;满足以下条件&#xff1a; 1 ~ n 这 n 个数在序列中各出现了一次 若第 i …