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;
}