LUOGU P2279 [HNOI2003]消防局的设立

传送门

解题思路

和以前做的一道题比较像,贪心+dfs,首先用一个优先队列,将所有的叶节点存到优先队列里,每次找到一个深度最大的,向上扩展2*2+1个节点,这些点都打上标记,然后把向上第6个点的当做叶节点继续放入优先队列,直到所有点被遍历。时间复杂度O(nlogn)。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
 
using namespace std;
const int MAXN = 1005;
 
inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}
 
struct Data{
    int dep,id;
    friend bool operator<(const Data A,const Data B) {
        return A.dep<B.dep;
    }
};
 
int n,k,head[MAXN],cnt,du[MAXN],num,deep[MAXN];
int to[MAXN<<1],nxt[MAXN<<1],ans;
bool vis[MAXN];
priority_queue<Data> Q;
 
inline void add(int bg,int ed){
    to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}
 
void dfs(int x,int fa,int d){
    deep[x]=d;
    if(du[x]==1 && x!=1) {Q.push(Data{d,x});return;}
    for(register int i=head[x];i;i=nxt[i]){
        int u=to[i];if(u==fa) continue;
        dfs(u,x,d+1);
    }
}
 
void dfs2(int x,int fa,int len){
    if(len==k*2+1) {if(!vis[x]) Q.push((Data){deep[x],x});return;}  
    vis[x]=1;
    for(register int i=head[x];i;i=nxt[i]){
        int u=to[i];if(u==fa) continue;
        dfs2(u,x,len+1);
    }
}
 
int main(){
    n=rd();int x;k=2;
    for(int i=1;i<n;i++){
        x=rd();
        add(x,i+1),add(i+1,x);
        du[x]++,du[i+1]++;
    }
    dfs(1,0,0);
    while(Q.size()){
        Data now=Q.top();Q.pop();
        if(vis[now.id]) continue;
//      cout<<now.id<<endl;
        dfs2(now.id,0,0);ans++;
    }
    cout<<ans<<endl;
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/sdfzsyq/p/9682871.html