CF963B Destruction of a Tree(思维+贪心)

题目告诉我们偶数度数才能删除,我们观察hint,发现他们的叶子结点是放在最后删除的

这点启发了我们,为什么要把叶子结点放在最后删呢,因为他的度数一定是1,也就是必须父亲删了他才能删。

所以,当儿子的个数为偶数,一定是父节点删了才能删他。从这方面考虑过去,当儿子节点为奇数呢?

我们发现,除了根节点外,其他节点可以在这个时候删除,因为他还有一条连在父亲的边。

但是他也可以选择不删啊,等其他点删了再说,为了避免无谓的讨论,我们需要一种固定的删法

所以我们可以想到从叶子往上求,能删就删,之后再从根往下,看看能否把所有都删除。注意特判根

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int N=4e5+10;
const int inf=1e9;
int h[N],e[N],ne[N],idx;
int st[N];
int vis[N],f[N];
vector<int> ans;
int sign;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){
    int i;
    int cnt=0;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        f[j]=u;
        dfs(j,u);
        if(vis[j]){
            continue;
        }
        else{
            cnt++;
        }
    }
    if(cnt%2&&u!=1){
        vis[u]=1;
        ans.push_back(u);
    }
    if(u==1){
        sign=cnt;
    }
}
void dfs1(int u,int fa){
    int i;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        if(vis[f[j]]&&!vis[j]){
            ans.push_back(j);
            vis[j]=1;
        }
        dfs1(j,u);
    }
}
int main(){
    ios::sync_with_stdio(false);
    memset(h,-1,sizeof h);
    int i;
    int n;
    cin>>n;
    for(i=1;i<=n;i++){
        int x;
        cin>>x;
        if(x!=0){
            add(x,i);
            add(i,x);
        }
    }
    dfs(1,0);
    if(!vis[1]&&sign%2==0){
        ans.push_back(1);
        vis[1]=1;
    }
    dfs1(1,0);
    if((int)ans.size()<n){
        cout<<"NO"<<endl;
    }
    else{
        cout<<"YES"<<endl;
        for(auto x:ans){
            cout<<x<<endl;
        }
    }
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13739497.html