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

· · 题解

{\color{orange}\text{欢迎拜访我这个蒟蒻的博客}}

此题的算法标签为:贪心、dfs,但我只用贪心就过了(用dp也可以

思路

因为图中有n个点和n-1条边,所以这是一棵树,处理时处理单个节点就行了。

贪心思路:找最深的节点并在其祖父节点上建造消防局:

1.构造树的节点i

因为树节点要按深度d排序,所以要记录树节点的原编号s,以便查询其父亲节点f[i]、覆盖程度p[i]

struct node{
    int d,s;
}a[1010];
int n,ans,f[1010],p[1010];
{\color{red}\text{如果把\textit{f}、\textit{p}包装进结构体\textit{node}}}$,${\color{red}\text{父亲节点所对应的值便无法查询}}

2.读入处理并排序

f[i]$只有$n-1$个,第一个节点的$s$要置成$1
bool cmp(node x,node y){
    return x.d>y.d;
} int main(){
    scanf("%d",&n);
    a[1].s=1;
    for(int i=2;i<=n;i++){
        scanf("%d",f+i);
        a[i].d=a[f[i]].d+1;
        a[i].s=i;
    } sort(a+1,a+n+1,cmp);

3.按照思路,建造消防局 不用dfs,不用树遍历:

3:消防局覆盖度; 2:消防局儿子父亲节点; 1:消防局孙子祖父节点; 0:消防局无法覆盖节点。 ```cpp for(int i=1;i<=n;i++){ //(1)继承祖先节点覆盖 p[a[i].s]=max(p[a[i].s], max(p[f[a[i].s]]-1, p[f[f[a[i].s]]]-2)); //(2)如果当前节点未被覆盖,在其祖父节点上建造消防局 if(!p[a[i].s]){ ans++; //①覆盖祖父节点 p[f[f[a[i].s]]]=3; //②覆盖父亲、当前节点 p[f[a[i].s]]=2; p[a[i].s]=1; //③覆盖曾祖父、玄祖父 p[f[f[f[a[i].s]]]]= max(p[f[f[f[a[i].s]]]],2); p[f[f[f[f[a[i].s]]]]]= max(p[f[f[f[f[a[i].s]]]]],1); } } ``` 然后这里的$ans$就是答案了。 ## 以下是完整代码 ```cpp #include <bits/stdc++.h> using namespace std; struct node{ int d,s; }a[1010]; int n,ans,f[1010],p[1010]; bool cmp(node x,node y){ return x.d>y.d; } int main(){ scanf("%d",&n); a[1].s=1; for(int i=2;i<=n;i++){ scanf("%d",f+i); a[i].d=a[f[i]].d+1; a[i].s=i; } sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ p[a[i].s]=max(p[a[i].s], max(p[f[a[i].s]]-1, p[f[f[a[i].s]]]-2)); if(!p[a[i].s]){ ans++; p[f[f[a[i].s]]]=3; p[f[a[i].s]]=2; p[a[i].s]=1; p[f[f[f[a[i].s]]]]= max(p[f[f[f[a[i].s]]]],2); p[f[f[f[f[a[i].s]]]]]= max(p[f[f[f[f[a[i].s]]]]],1); } } printf("%d\n",ans); return 0; } ``` 谢谢观看此题解的巨佬观众们!