题解【洛谷P2279】[HNOI2003]消防局的设立

题目描述

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

题解

比较简单的贪心。

因为我们要覆盖每一个点,因此我们需要每次贪心地选择还没有被选择的深度最深的点\(p\)

\(q\)\(p\)的爷爷,则覆盖所有与\(q\)的距离为\(1\)\(2\)的点。

不难得出\(AC\)代码。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <vector>

using namespace std;

inline int gi()
{
	int f = 1, x = 0;
	char c = getchar();
	while (c < '0' || c > '9')
	{
		if (c == '-') f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		x = x * 10 + c - '0';
		c = getchar();
	}
	return f * x;
}

int n, m, mm, dis[1003], ans, u, v, fa[1003], deep[1003], r[1003];
vector <int> w[1003];

int main()
{
	n = gi();
	fa[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		int x = gi();
		fa[i] = x, dis[i] = dis[x] + 1, w[x].push_back(i);
	}
	for (int i = 1; i <= n; i++)
	{
		int k = 0, mk = -1;
		for (int j = 1; j <= n; j++)
		{
			if (!r[j] && dis[j] > mk) k = j, mk = dis[j];
		}
		if (k == 0)
		{
			printf("%d\n", i - 1);
			return 0;
		}
		m = fa[fa[k]], r[m] = 1, r[fa[m]] = 1, r[fa[fa[m]]] = 1;
		for (int j = 0; j < w[m].size(); j++)
		{
			u = w[m][j], r[u] = 1;
			for (int l = 0; l < w[u].size(); l++)
			{
				r[w[u][l]] = 1;
			}
		}
		mm = fa[m];
		for (int j = 0; j < w[mm].size(); j++)
		{
			r[w[mm][j]] = 1;
		}
	}
	return 0;
}
posted @ 2019-07-03 15:20  csxsi  阅读(187)  评论(0编辑  收藏  举报