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; }
没有人不辛苦,只有人不喊疼