[HNOI2003]消防局的设立 题解

[HNOI2003]消防局的设立 题解

题目描述

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。

输出格式

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

样例

input:

6
1
2
3
4
5

output

2


样例分析:

我们用样例进行分析
如图:
六个点的单链
可以想到,当消防局在1和4时可满足条件,此时答案为2
(推荐一个网址,画图贼棒)


思路

分析了样例后,这个题到底该怎么来做呢?
首先,因为每个点可以覆盖与它距离为2的所有点
那么我们可以想到的就是让每个点都尽量覆盖更多的点

即贪心

此题的一个做法即为从树的最深的一个节点开始进行
那么我们就可以按照深度进行排序
接着便利每一个可以覆盖的点
并把vis置为true
每次放置消防局时便跳过已经遍历了的
这样就可以得到我们的答案了

坑点

  1. 不是每个点都只遍历一次,故每次更新时,直接bfs即可,不需要剪枝
    本人被坑了1小时,亏哭了
  2. 距离为2的点并不包括自己!!!

code

#include <cstdio>
#include <vector>
#include <cctype>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
template <class T>
void rd(T &x)
{
    #define gc getchar()
    x = 0;
    char c = gc;
    ll f = 1;
    while (!isdigit(c)) {if (c == '-') f = -1;c = gc;}
    while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = gc;
    x *= f;
    #undef gc
}
template <class T>
void pt(T x)
{
    if (x < 0)
        putchar ('-'), x = (~x) + 1;
    if (x > 9)
        pt(x / 10);
    putchar ((x % 10) ^ 48);
}
const int N = 1005;
int n;
vector <int> Graph[N];
int deep[N], ans, fa[N];
bool vis[N];
struct node
{
    int id, deep;
    bool operator < (const node &x)
    {
        return deep > x.deep;
    }
}a[N];
void dfs(int x)
{
    vis[x] = 1;
    for (int i = 0;i < (int)Graph[x].size(); i++)
        if (!vis[Graph[x][i]])
        {
            fa[Graph[x][i]] = x;
            a[Graph[x][i]].deep = a[x].deep + 1;
            dfs(Graph[x][i]);
        }
}
void update(int x, int tim)
{
    // if (tim <= 2)
    // printf("x = %d, tim = %d\n", x, tim);
    if (tim > 2)
        return;
    vis[x] = 1;
    for (int i = 0;i < (int)Graph[x].size(); i++)
        // if (!vis[Graph[x][i]])
            update(Graph[x][i], tim + 1);
}
int main() 
{
    rd(n);
    for (int i = 1;i <= n; i++)
        fa[i] = i;
    a[1].id = 1;
    for (int i = 2, x;i <= n; i++)
    {
        a[i].id = i;
        rd(x);
        Graph[x].push_back(i);
        Graph[i].push_back(x);
    }
    dfs(1);
    for (int i = 1;i <= n; i++)
        vis[i] = 0;
    sort(a + 1, a + n + 1);
    int last = 0;
    while (1)
    {
        bool f = 1;
        for (int i = last + 1;i <= n; i++)
            if (!vis[a[i].id])
            {
                last = i;
                f = 0;
                break;
            }
        if (f)
            break;
        ans++;
        // printf ("a[last].id = %d\n", a[last].id);
        int x = fa[fa[a[last].id]];
        update(x, 0);
    }
    pt(ans);
    return 0;
}

Thanks for reading!

原创文章 23 获赞 41 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43537070/article/details/102689824
今日推荐