[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,一经查实,立即删除!

相关文章

dnSpy 强大的.Net反编译软件

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

小奇探险

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

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

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

[NOIP 2009 提高组]最优贸易

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

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

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

P3265 [JLOI2015]装备购买

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

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

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

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

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

失配树(border树)

4和6没有border关系 举例子&#xff1a; 当i 3时&#xff0c;j fa[i-1] fa[2] 0 s[j1] s[1] a s[3] 所以把i 3点的父亲设为j1 1 P5829 [模板]失配树

魔方俱乐部

爆肝感动三更题目思路90分代码&#xff08;MLE&#xff09;题解代码实现题目 fateice 来到了魔方俱乐部旅行。 魔方俱乐部有N个分部&#xff0c;每个分部均有且仅有一个虫洞&#xff0c;但是这虫洞只能通往一个分部。 每个分部有一个 orzFang 价值&#xff0c;第i个分部的 or…

模板:最大匹配

文章目录前言代码前言 匈牙利算法 可以解决的问题&#xff1a; &#xff08;原谅我的偷懒&#xff09; &#xff08;原谅我的水文&#xff09; 代码 #include<bits/stdc.h> using namespace std; #define ll long long const int N3e5100; const int mod1e97; int n,…

Stack Overflow 监控系统内部架构初探

Stack Exchange 架构主管 Nick Craver 在最近的一篇文章中介绍了他们的监控系统。他在文章中讨论了监控策略背后的理念和动机&#xff0c;并介绍了他们的工具集——主要是 Bosun、Grafana 和 Opserver。Stack Overflow 及其姐妹站点 Stack Exchange 运行在.NET 和 MS SQL Serve…

P5829 【模板】失配树

P5829 【模板】失配树 题目&#xff1a; 题解&#xff1a; 参考题解 我们先想一个问题&#xff1a;如何求出一个字符串的所有border&#xff1f; 如果一个字符串既是 S的前缀又是 S 的后缀&#xff0c;那么我们把 SS 自己平移一下就可以前后重合&#xff0c;然后我们就可以继…

[JLOI2015]战争调度

文章目录题目题解代码实现题目 脸哥最近来到了一个神奇的王国&#xff0c;王国里的公民每个公民有两个下属或者没有下属&#xff0c;这种关系刚好组成一个 n 层的完全二叉树。 公民 i 的下属是 2 * i 和 2 * i 1。最下层的公民即叶子节点的公民是平民&#xff0c; 平民没有下…

使用PerfView监测.NET程序性能(一):Event Trace for Windows

前言&#xff1a;在日常项目开发中&#xff0c;我们时不时会遇到程序占用了很高CPU的情况&#xff0c;可能是程序里某些未经优化的代码或者Bug&#xff0c;或者是程序运行压力太大。无论是什么原因&#xff0c;我们总希望能看到到底是哪个方法占用了如此高的CPU。微软为我们提供…

【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

我似乎很少写这种算法博客可持久化线段树概念概念介绍&#xff08;类比帮助理解&#xff09;简单分析一下时间和空间复杂度&#xff08;内容池&#xff09;模板结构体变量建树模板单点修改模板单点查询模板区间修改模板&#xff08;pushup&#xff09;区间修改模板&#xff08;…

P3258 [JLOI2014]松鼠的新家

文章目录题意&#xff1a;题解&#xff1a;树上差分代码&#xff1a;树链剖分代码&#xff1a;P3258 [JLOI2014]松鼠的新家题意&#xff1a; n个点&#xff0c;n-1条边&#xff0c;给出每个点的拜访顺序&#xff0c;问每个点经过几次&#xff08;最后一次移动不算拜访&#xf…

[SOCI2005]最大子矩阵(DP) + [JXOI2018]守卫(DP) + [CQOI2016]手机号码(数位DP)[各种DP专练]

DP专练博客 DP专练T1&#xff1a;最大子矩阵题目题解代码实现T2&#xff1a;守卫题目题解代码实现T3&#xff1a;手机号码题目题解代码实现T1&#xff1a;最大子矩阵 题目 这里有一个n*m的矩阵&#xff0c;请你选出其中k个子矩阵&#xff0c;使得这个k个子矩阵分值之和最大。…

IdentityServer4-EF动态配置Client和对Claims授权(二)

本节介绍Client的ClientCredentials客户端模式&#xff0c;先看下画的草图&#xff1a;一、在Server上添加动态新增Client的API 接口。为了方便测试&#xff0c;在Server服务端中先添加swagger&#xff0c;添加流程可参考&#xff1a;https://www.cnblogs.com/suxinlcq/p/67575…

P3178 [HAOI2015]树上操作

P3178 [HAOI2015]树上操作 题意&#xff1a; 题解&#xff1a; 这已经是很裸的树链剖分了。。。 直接套模板 代码&#xff1a; #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespac…