在某背景下做了此题。此题有解为树形DP,这里是贪心的题解。
思路:考虑到 一个消防局可以扑灭与他距离 <= 2 的所有点。那么我们每隔4个点放一个消防局是最优的。
在 dfs 中:我们用数组 f[] 标记每个点 某种程度上可以说 abs(f[x]-5) 就是 x 到消防局的距离。当 f[x] == 5 时 那我们另 f[x] == 0 即,把这个看为一个消防局 ans ++;
还有一个地方就是处理一下边界,即开始的点,如果走到了这里而这里距离最近的消防局的距离大于等于3,也就是这里没有被消防局覆盖,那就只能在这里也加上一个消防局了。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 1000 + 10;
int tot = 0, ans = 0;
int first[MAXN], nxt[MAXN << 1], f[MAXN];
struct edge{
int from, to;
}es[MAXN << 1];
void build(int ff, int tt)
{
es[++tot] = (edge){ff,tt};
nxt[tot] = first[ff];
first[ff] = tot;
}
void dfs(int x, int p = -1)
{
int maxn = -MAXN, minn = MAXN;
for(int i = first[x]; i != -1; i = nxt[i])
{
int v = es[i].to;
if(v != p)
{
dfs(v, x);
maxn = max(f[v], maxn);
minn = min(f[v], minn);
}
}
if(maxn + minn <= 3)
f[x] = minn + 1;
else f[x] = maxn + 1;
if(minn == MAXN)
f[x] = 3;
if(f[x] == 5)
{
ans ++;
f[x] = 0;
}
else if(p == -1 && f[x] >= 3)
ans ++;
}
int main()
{
int n;
cin >> n;
memset(first,-1,sizeof(first));
for(int i = 1; i < n; i ++)
{
int v;
scanf("%d",&v);
v --;
build(i,v);
build(v,i);
}
dfs(0);
cout << ans << endl;
return 0;
}
P.S 这种做法 是跟这个博客学的。尊重知识产权从我做起。