Destruction of a Tree (dfs+思维)

Destruction of a Tree

You are given a tree (a graph with n vertices and n - 1 edges in which it's possible to reach any vertex from any other vertex using only its edges).

A vertex can be destroyed if this vertex has even degree. If you destroy a vertex, all edges connected to it are also deleted.

Destroy all vertices in the given tree or determine that it is impossible.


Input

The first line contains integer n (1 ≤ n ≤ 2·105) — number of vertices in a tree.

The second line contains n integers p1, p2, ..., pn (0 ≤ pi ≤ n). If pi ≠ 0 there is an edge between vertices i and pi. It is guaranteed that the given graph is a tree.

Output

If it's possible to destroy all vertices, print "YES" (without quotes), otherwise print "NO" (without quotes).

If it's possible to destroy all vertices, in the next n lines print the indices of the vertices in order you destroy them. If there are multiple correct answers, print any.

Examples
Input
5
0 1 2 1 2
Output
YES
1
2
3
5
4
Input
4
0 1 2 3
Output
NO
Note

In the first example at first you have to remove the vertex with index 1 (after that, the edges (1, 2) and (1, 4) are removed), then the vertex with index 2 (and edges (2, 3) and (2, 5) are removed). After that there are no edges in the tree, so you can remove remaining vertices in any order.


题意:让我们每次删除度数为偶数的节点,问最后能否把所有的点删除,如果能全部删除,输出YES并且输出每个节点删除顺序,否则输出NO

思路:这道题乍一看比较容易想出大体的框架,可以用dfs可以用bfs,先找出偶数度的点,开始删除,但是就会发现一个问题,如果我们删除掉一下偶数度的点后,由于边数的减少可能会使得某些其他点原来是偶数度,结果一删其他点它变成了奇数度,就再也变不回去了,导致原本可以完全删除的情况变得不可完全删除,由此我们可以贪心消除靠近叶子节点的偶数点,自下而上进行检查删除,这样他对于其他点的影响可以降到最小

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
using namespace std;
const int maxn = 2e5+10;
int n,pre[maxn],vis[maxn],degree[maxn];
vector<int> G[maxn];
vector<int> ans;
stack<int> st;
void dfs1(int p,int x){
    st.push(x);
    pre[x] = p;
    for(int i = 0; i < G[x].size(); i++){
        int y = G[x][i];
        if(y == p) continue;//直往下存儿子
        dfs1(x,y);
    }
}
void dfs2(int x){
    ans.push_back(x);
    vis[x] = 1;
    for(int i = 0; i < G[x].size(); i++){
        int y = G[x][i];
        degree[y]--;
        if(y == pre[x]) continue;//父亲节点不用管了,因为这个点一定是从父亲节点过来的
        if(vis[y]) continue;//删过的点不用管了
        if(degree[y] % 2 == 0) dfs2(y);
    }
}
int main(){
    memset(vis,0,sizeof(vis));
    memset(degree,0,sizeof(degree));
    scanf("%d",&n);
    for(int i = 1; i <= n; i++){
        int x;
        scanf("%d",&x);
        if(x){
            G[i].push_back(x);
            G[x].push_back(i);
            degree[i]++;
            degree[x]++;
        }
    }
    dfs1(0,1);//深搜将节点用栈储存,这样顶部是叶子节点
    while(!st.empty()){
        int x = st.top();
        st.pop();
        if(degree[x] % 2 == 0)
            dfs2(x);
    }
    if(ans.size() == n){
        printf("YES\n");
        for(int i = 0; i < ans.size(); i++){
            printf("%d\n",ans[i]);
        }
    }
    else{
        printf("NO\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/80327009