本题的贪心策略是:每次删除连到叶子结点的dfs链上离根最远的偶数度的结点
greed is good
实现方法是先维护一个degree[i]表示第i个点有多少个度,然后dfs,当每一个结点的所有子节点被访问后准备返回时判断当前结点degree的奇偶性,如果是偶数就删除,是奇数就什么都不做。这样能保证你删除的结点【的子孙】度数都是奇数,及保证删除了【离根最远的偶数度的结点】。每次删除要把它父亲和son的degree都减1,并且如果son的degree减完以后是偶数的话就把son也删除。(以为这样能保证该son是这条链上离root的最远节点,及该son的子孙度数都一定是奇数)注意如果parent的degree减完是偶数的话我们不能删掉parent,因为parent的所有子结点没有访问完,我们无法确定parent是不是离根最远的偶数度结点。
1 #include<iostream> 2 #include<vector> 3 #define MAXN 200000 4 using namespace std; 5 6 int n; 7 int ans[MAXN+5],root,vis[MAXN+5],del[MAXN+5]; 8 int degree[MAXN+5],parent[MAXN+5];//第i个节点有多少度 ,每个节点的parent 9 vector<int> edge[MAXN+5]; 10 int top; 11 //从下往上删偶数度的点 12 13 void Del(int node){//删除node点,并且递归删除新的可删除的点 14 ans[++top]=node; 15 del[node]=1;//把当前node删掉 16 for(int i=0;i<edge[node].size();i++){ 17 int v=edge[node][i]; 18 if( del[v] ) continue; 19 degree[v]-=1;//一个结点被删除后只会影响他 parent和son的degree 20 if(degree[v]%2==0 && parent[node]!=v) Del(v);//不能删他的父亲结点,因为不知道父亲节点是不是离根最远的偶数度结点; 21 //但如果是son的话可以保证,因为该节点后代的度数都是基数 22 } 23 } 24 25 void dfs(int node){ 26 vis[node]=1; 27 28 for(int i=0;i<edge[node].size();i++){ 29 int v=edge[node][i]; 30 if(vis[v]) continue; 31 parent[v]=node; 32 dfs(v); 33 } 34 35 if(degree[node]%2==0) Del(node); //如果偶数度那删掉 36 37 } 38 39 int main(){ 40 41 cin>>n; 42 for(int i=1;i<=n;i++) { 43 int v; cin>>v; 44 if(v==0) root=i; 45 else{ 46 edge[i].push_back(v); 47 edge[v].push_back(i); 48 } 49 } 50 51 for(int i=1;i<=n;i++) degree[i]=edge[i].size(); 52 dfs(root); 53 54 if( top==n ){ 55 cout<<"YES"<<endl; 56 for(int i=1;i<=n;i++) cout<<ans[i]<<endl; 57 } 58 else cout<<"NO"; 59 60 61 62 return 0; 63 }