题目链接:https://www.luogu.org/problemnew/show/P2279
解析部分请看这位大佬的博客:https://www.luogu.org/blog/contributation/solution-p2279
这道题目的代码:
//核心是dis数组,即dis[i]表示距离i节点最近的消防站的距离
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e3+10, INF=0x3f3f3f3f;
int n, ans, d[N], f[N], seq[N], dis[N];
bool cmp(int a, int b) {
return d[a]>d[b];
}
int main() {
memset(dis, INF, sizeof(dis));
cin >> n;
seq[1]=1;
for (int i=2; i<=n; i++) {
cin >> f[i];
d[i]=d[f[i]]+1;
seq[i]=i;
}
sort(seq+1, seq+n+1, cmp);按照深度由大到小间接排序
for (int i=1; i<=n; i++) {
int cur=seq[i], last=f[cur], lasts=f[last];//每次选取深度最大
dis[cur]=min(dis[cur], min(dis[last]+1, dis[lasts]+2));//维护dis数组
if (dis[cur]>2) {//如果它无法被覆盖到
dis[lasts]=0;//那么在它的父亲的父亲上设立消防站
ans++;
dis[f[lasts]]=min(dis[f[lasts]], 1), dis[f[f[lasts]]]=min(dis[f[f[lasts]]], 2);//维护dis数组
}
}
cout << ans;
return 0;
}
//理解这段代码要从在父亲的父亲设站开始,因为事实上这才是我们想要做的开始的地方,之后只需向上维护dis数组,其余节点会在每次选深度最大的那一步进行更新
ps:另外请区分树的最大独立集和最小覆盖,最小覆盖强调的是将整幅图覆盖用最少的点覆盖,而最大独立集则是按照该点选了,则它的子节点和父节点一定不能选,如果不选,则子节点和父节点按照题目进行选择。https://www.luogu.org/problemnew/show/P1352可将这个题和上面消防局那个题进行对比,来进行更好的理解。
关于大佬说的普适性,这里给出最小k覆盖的代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=1e3+10, INF=0x3f3f3f3f;
int n, k, ans, cnt, d[N], f[N], ancestor[N], seq[N], dis[N];
//用ancestor数组来存向上k距离的各个节点
bool cmp(int a, int b) {
return d[a]>d[b];
}
void update(int cur) {
memset(ancestor, 0, sizeof(ancestor));
ancestor[0]=cur;
for (int i=1; i<=k; i++) {
if (f[ancestor[i-1]]==0) break;
ancestor[i]=f[ancestor[i-1]];
}
return ;
}
int main() {
memset(dis, INF, sizeof(dis));
cin >> n;
seq[1]=1;
k=2;
for (int i=2; i<=n; i++) {
cin >> f[i];
d[i]=d[f[i]]+1;
seq[i]=i;
}
sort(seq+1, seq+n+1, cmp);
for (int i=1; i<=n; i++) {
update(seq[i]);
for (int j=1; j<=k; j++) {
if (ancestor[j]==0) break;
dis[ancestor[0]]=min(dis[ancestor[0]], dis[ancestor[j]]+j);
}
if (dis[ancestor[0]]>k) {
dis[ancestor[k]]=0;
ans++;
update(ancestor[k]);
for (int j=1; j<=k; j++) {
if (ancestor[j]==0) break;
dis[ancestor[j]]=min(dis[ancestor[j]], j);
}
}
}
cout << ans;
return 0;
}
//复杂度O(nk)