codeforces 963B Destruction of a Tree

B. Destruction of a Tree
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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
Copy
5
0 1 2 1 2
output
Copy
YES
1
2
3
5
4
input
Copy
4
0 1 2 3
output
Copy
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.

 

题意:

给出一棵树,每次可以删除一个度数为偶的点 和 与这个点相连的边。

问是否存在一种方案吧整个树都删除,如果存在,输出任意方案。

题解:

分析:叶节点一定是不能直接删掉的(度数为1),因此要想删掉叶节点,必须先删掉其父节点。

如果父节点的度数为偶,则可以将其删去,

如果父节点的度数为奇,那么要想删掉该父节点,必须先删掉此父节点的父节点………………

 

是不是有一点向根递归的感觉。

刚才遗漏了很多细节,现在来完善这个思路:

设一个节点的子节点中,度数为奇的子节点数量为cnt[0],度数为偶的子节点数量为cnt[1]

这个节点的度数deg=cnt[0]+cnt[1]+1

度数为偶的子节点要首先删掉的,那么该节点剩下的度数就是deg-cnt[1]

如果(deg-cnt[1])%2==0,那么这个点也可以直接删掉。

如果(deg-cnt[1])%2==1,那么这个点不能直接删掉,需要先删掉其父节点。

那么一个有意思的树形dp就出来了,v[i]表示将 i 的子节点中能直接删掉的删掉后,i 能否直接删掉(v[i]==0表示不能,v[i]==1表示能)。

 

最后看v[root]是否为1就可以判断yes,no。

输出方案:

对于一个节点,先删除其子节点中能直接删除的,然后将这个节点删除,这样其不能删除的子节点就可以删除了,将其删除。

递归处理,输出即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<ctime>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 #include<cmath>
 8 #include<string>
 9 using namespace std;
10 int read(){
11     int xx=0,ff=1;char ch=getchar();
12     while(ch>'9'||ch<'0'){if(ch=='-')ff=-1;ch=getchar();}
13     while(ch>='0'&&ch<='9'){xx=xx*10+ch-'0';ch=getchar();}
14     return xx*ff;
15 }
16 const int maxn=200010;
17 int N,root;
18 int lin[maxn],len,deg[maxn];
19 struct edge{
20     int y,next;
21 }e[maxn<<1];
22 inline void insert(int xx,int yy){
23     e[++len].next=lin[xx];
24     lin[xx]=len;
25     e[len].y=yy;
26     deg[xx]++;
27 }
28 bool v[maxn];//v==1:can delete now,v==0:can not delete now
29 int cnt[maxn][2];
30 bool dfs(int x,int fa){
31     for(int i=lin[x];i;i=e[i].next)
32         if(e[i].y!=fa)
33             cnt[x][dfs(e[i].y,x)]++;
34     if((deg[x]-cnt[x][1])%2==0)
35         v[x]=1;
36     else
37         v[x]=0;
38     return v[x];
39 }
40 void print(int x,int fa){
41     for(int i=lin[x];i;i=e[i].next)
42         if(e[i].y!=fa)
43             if(v[e[i].y])
44                 print(e[i].y,x);
45     printf("%d
",x);
46     for(int i=lin[x];i;i=e[i].next)
47         if(e[i].y!=fa)
48             if(!v[e[i].y])
49                 print(e[i].y,x);
50 }
51 int main(){
52     //freopen("in.txt","r",stdin);
53     N=read();
54     for(int i=1;i<=N;i++){
55         int temp=read();
56         if(!temp)
57             root=i;
58         else
59             insert(i,temp),insert(temp,i);
60     }
61     if(dfs(root,0)){
62         puts("YES");
63         print(root,0);
64     }
65     else
66         puts("NO");
67     return 0;
68 }
View Code
原文地址:https://www.cnblogs.com/lzhAFO/p/8884155.html