题目链接:传送门

题目大意:

  给定一棵树(N个基地N-1条边);

  用半径为2的消防局覆盖这N个基地,问最小的消防局数量。

  (树上距离为k的最小覆盖问题)

思路:

  每次贪心地找到不被覆盖的最深的一个节点,在它的祖父处放一个消防局。

  这个消防局所在位置即能将这个节点覆盖到的离它最远的点。

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e3 + ; int N;
vector <int> Edge[MAX_N];
int dep[MAX_N], fa[MAX_N];
bool vis[MAX_N]; int findlower()
{
int lower = , ind = ;
for (int i = ; i <= N; i++) {
if (!vis[i] && dep[i] > lower) {
lower = dep[i];
ind = i;
}
}
return ind;
} void update(int x)
{
x = fa[fa[x]];
for (int i = ; i < (int)Edge[x].size(); i++) {
int y = Edge[x][i];
vis[y] = true;
for (int j = ; j < (int)Edge[y].size(); j++) {
int z = Edge[y][j];
vis[z] = true;
}
}
} int solve()
{
memset(vis, false, sizeof vis);
int ans = ;
int cur = findlower();
while (cur) {
update(cur);
ans++;
cur = findlower();
}
return ans;
} void build(int x)//不妨把编号为1的点当作根节点
{
for (int i = ; i <= N; i++) {
dep[i] = -;
fa[i] = i;
}
dep[x] = ;
queue <int> Q;
Q.push(x);
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = ; i < (int)Edge[u].size(); i++) {
int v = Edge[u][i];
if (dep[v] < ) {
dep[v] = dep[u] + ;
fa[v] = u;
Q.push(v);
}
}
}
} int main()
{
cin >> N;
for (int u = ; u <= N; u++) {
int v;
cin >> v;
Edge[u].push_back(v);
Edge[v].push_back(u);
}
int ans = N;
build();
ans = min(ans, solve());
cout << ans << endl;
return ;
}

  前面有点想多了,因为题目中给出的ai < i,所以不需要build直接拿题目中给的树来用就好了。。

  不过也无伤大雅。

  然后是膜大佬学到的代码:

  求树上距离为k的最小覆盖都可以这样做:

  (时间复杂度为O(N * k))

#include <bits/stdc++.h>

using namespace std;
const int MAX_N = 1e3 + ;
const int INF = 0x3f3f3f3f; struct Node{
int dep, ind;
Node(int d = , int i = ) : dep(d), ind(i) {}
bool operator < (const Node& x) const {
return dep > x.dep;
}
}nodes[MAX_N]; int fa[MAX_N], dis[MAX_N]; int main()
{
int N;
cin >> N;
nodes[] = Node(, );
fa[] = ;
dis[] = INF;
for (int i = ; i <= N; i++) {
scanf("%d", fa+i);
dis[i] = INF;
nodes[i].ind = i;
nodes[i].dep = nodes[fa[i]].dep + ;
}
sort(nodes+, nodes+N+);
int ans = ;
for (int i = ; i <= N; i++) {
int u = nodes[i].ind;
int v = fa[u];
int w = fa[v];
if (dis[u] > && dis[v] > && dis[w] > ) {
ans++;
dis[u] = ;
dis[v] = min(dis[v], );
dis[w] = min(dis[w], );
dis[fa[w]] = min(dis[fa[w]], );
dis[fa[fa[w]]] = min(dis[fa[fa[w]]], );
}
}
cout << ans << endl;
return ;
}

  

P2279 消防局的设立(贪心+dp)的更多相关文章

  1. P2279 消防局的设立 (树形DP or 贪心)

    (点击此处查看原题) 树形DP写法 看到这个题的要求,很容易相到这是一个树形DP的问题,但是dp数组应该如何设计并转移才是关键 dp[i][0]代表当前结点可以向上覆盖2层,自身一定被覆盖dp[i][ ...

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

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

  3. BZOJ 1217: [HNOI2003]消防局的设立( 贪心 )

    一个简单的贪心, 我们只要考虑2个消防局设立的距离为5时是最好的, 因为利用最充分. 就dfs一遍, 再对根处理一下就可以了. 这道题应该是SGU某道题的简化版...这道题距离只有2, 树型dp应该也 ...

  4. [HNOI2003]消防局的设立 (贪心)

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

  5. 【题解】P2279消防局的设立

    [题解][P2279 HNOI2003]消防局的设立 又是一道贪心. 随便指定一个点为根,可以知道在覆盖了一个节点的子树的情况下,消防站越高越好.那么我们就贪心吧.\(trick\)是按深度\(pus ...

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

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

  7. P2279 [HNOI2003]消防局的设立 贪心or树形dp

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

  8. [HNOI2003]消防局的设立 树形dp // 贪心

    https://www.luogu.org/problemnew/show/P2279 一开始就想到了贪心的方法,不过一直觉得不能证明. 贪心的考虑是在深度从深到浅遍历每个结点的过程中,对于每个没有覆 ...

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

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

随机推荐

  1. servlet/和/*匹配的区别

    两者真正的区别是,两者的长度不同,根据最长路径匹配的优先级,/*比/更容易被选中,而/的真正含义是,缺省匹配.既所有的URL都无法被选中的时候,就一定会选中/,可见它的优先级是最低的,这就两者的区别.

  2. 套接字编程,创建套接字socket

    1.套接字地址结构: struct sockaddr { sa_family_t sa_family; char sa_data[14]; }; 其中,成员sa_family表示套接字的协议族类型,对 ...

  3. windows中mysql5.7保存emoji表情

    1.找到my.ini文件,修改一下配置: [client] default-character-set=utf8mb4 [mysqld] character-set-client-handshake ...

  4. linux系统用户和组管理

    用户和组管理 Linux是多用户多任务的网络操作系统,作为网络管理员,掌握用户的组的创建与管理至关重要. 学习要点: 了解用户和组的群的配置文件. 熟悉掌握Linux下用户的创建和维护管理. 熟悉掌握 ...

  5. linux文件管理 文件权限

    文件权限介绍 [root@ssgao1987 ~]# ls -l 总用量 24 -rw-------. 1 root root  1161 7月   8 10:30 anaconda-ks.cfg - ...

  6. 遍历所有子物体中renderer(渲染器)中的material(材质)并改变其alpha值实现若隐若现的效果

    using UnityEngine;using System.Collections;using UnityEngine.UI; public class CubeControl : MonoBeha ...

  7. day16-python常用的内置模块2

    logging模块的使用 一:日志是我们排查问题的关键利器,写好日志记录,当我们发生问题时,可以快速定位代码范围进行修改.Python有给我们开发者们提供好的日志模块,下面我们就来介绍一下loggin ...

  8. VSTO:使用C#开发Excel、Word【10】

    第二部分:.NET中的Office编程本书前两章介绍了Office对象模型和Office PIA. 您还看到如何使用Visual Studio使用VSTO的功能构建文档中的控制台应用程序,加载项和代码 ...

  9. 深入理解java虚拟机---虚拟机工具jinfo(十五)

    作用: 实时查看和调整虚拟机参数. jinfo 是jdk自带的一个工具,它可以用来查看正在运行的java应用程序的扩展参数(JVM中-X标示的参数):甚至支持在运行时修改部分参数. 1.通过以下的命令 ...

  10. 5.4 C++重载输入与输出操作符

    参考:http://www.weixueyuan.net/view/6382.html 总结: 在C++中,系统已经对左移操作符“<<”和右移操作符“>>”分别进行了重载,使其 ...