发布于 

Luogu 2279

Luogu 2279

本来Luogu给的标签是动态规划的,结果我动态规划好长时间都没有做出来。看了一下题解,发现都是贪心。。。。贪心的写法还是比较简单的。

题目来源: Luogu

题解

我们可以先对每个根节点分析:当我们把一个消防局放在根节点上时,它能够覆盖他的父节点、他的兄弟和他的祖父节点。而当我们把该消防局放在根节点的祖父节点上时,我们可以发现消防局同样可以覆盖这些节点,并且还能覆盖其他的节点。也就是说,这个题目是有局部最优解的,而且很明显的,因为该节点并不会影响其他节点的位置,所以没有后效性。因此我们可以使用贪心算法。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

int fa[1010];
int son[1010][1010];
bool flag[1010];

struct Point{
trueint x,depth;
true
truePoint(int x,int depth):x(x),depth(depth) {}

trueconst bool operator <(const Point& tmp)const{
truetruereturn depth<tmp.depth;
true}
};

priority_queue<Point> q;

void dfs(int x,int depth)
{
trueq.push(Point(x,depth));
truefor (int i = 1; i<=son[x][0]; i++)
truetruedfs(son[x][i],depth+1);
truereturn;
}

void fill(int x,int dis)
{
trueflag[x] = false;
trueif (dis==0)
truetruereturn;

trueif (x!=1)
truetruefill(fa[x],dis-1);
truefor (int i = 1; i<=son[x][0]; i++)
truetruefill(son[x][i],dis-1);
truereturn;
}

int main()
{
truememset(flag,true,sizeof(flag));
trueint n;
truescanf("%d",&n);

truefor (int i = 2; i<=n; i++)
true{
truetruescanf("%d",&fa[i]);
truetrueson[ fa[i] ][ ++ son[ fa[i] ][0] ] = i;
true}

truedfs(1,1);

trueint ans = 0;
truewhile (!q.empty())
true{
truetruePoint p = q.top(); q.pop();
truetrueif (flag[p.x])
truetrue{
truetruetrueans++;
truetruetruefill(fa[fa[p.x]],2);
truetrue}
true}

trueprintf("%d",ans);
}

本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站由 [@Songer](https://blog.songer.xyz/) 创建,使用 Stellar 作为主题。