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.
OutputIf 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.
Examples5 0 1 2 1 2
YES 1 2 3 5 4
4 0 1 2 3
NO
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; }