思路
题面中给出的数据结构很显然是一棵树,我们需要求能覆盖整棵树的最少的消防局数量。我们先按照要求输入,决定根节点(我这里是1号)之后按深度排序,从深度最深的节点开始检测。如果一个节点没有被覆盖,那么就覆盖他的爷爷节点,这样可以使覆盖面积最大,在覆盖时向两个方向扩散设置vis[i]标记。被标记过的点则跳过,没有被标记的点则把消防局设在爷爷处。由于我们的设置过程是按照深度由深到浅渐进,所以不会存在潜在的问题。
代码
// P2279.cpp
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
const int maxn = 4040;
struct edge
{
int to, next;
} edges[maxn];
int head[maxn];
int F[maxn];
stack<int> st;
bool vis[maxn];
int current = 0;
int n;
void addpath(int src, int dst)
{
edges[current].to = dst;
edges[current].next = head[src];
head[src] = current++;
}
void BFS()
{
queue<int> q;
q.push(1);
st.push(1);
while (!q.empty())
{
int curt = q.front();
q.pop();
for (int i = head[curt]; i != -1; i = edges[i].next)
if (edges[i].to != F[curt])
st.push(edges[i].to), q.push(edges[i].to);
}
}
void DFS(int p, int dep)
{
if (dep > 2)
return;
vis[p] = true;
for (int i = head[p]; i != -1; i = edges[i].next)
DFS(edges[i].to, dep + 1);
}
int main()
{
cin >> n;
fill(head, head + maxn, -1);
fill(vis, vis + maxn, false);
int num = -1;
for (int i = 2; i <= n; i++)
{
cin >> num;
F[i] = num;
addpath(num, i), addpath(i, num);
}
// going to solve;
BFS();
int ans = 0;
while (!st.empty())
{
int curt = st.top();
st.pop();
if (!vis[curt] && ++ans)
DFS(F[F[curt]], 0);
}
cout << ans;
return 0;
}