CodeForces - 963B Destruction of a Tree (dfs+思维题)

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

50 1 2 1 2

output

Copy

YES12354

input

Copy

40 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.

题目大意:给你一棵树,只能删除度数为偶数的节点,节点删除后,与它相连的边也会删除。问你能否把所有点删除。

解题思路:只要你能想到,如果一棵树,有偶数条边,那么他一定能被删除完!或者说,一棵树有奇数个节点,那么他肯定能被删除完!因为,如果边为奇数,每次删除偶数条边,最后肯定剩奇数个边啊!如果边为偶数,每次删除偶数条边,最后肯定能删除完!所以基于这个思想,我们递归的删除点即可。从根节点开始,如果某一棵子树他的节点个数为偶数(加上当前节点就为奇数了),那么就深搜这颗子树,递归删除。

#include <bits/stdc++.h>
using namespace std;  

vector<int> ch[200005];
int sz[200005];  

void getsize(int u, int pre)
{
    sz[u] = 1;
    for (int i = 0; i < ch[u].size(); ++i)
    {
        if (ch[u][i] != pre)
        {
            getsize(ch[u][i], u);
            sz[u] += sz[ch[u][i]];
        }
    }
}  

void dfs(int u, int pre)
{
    for (int i = 0; i < ch[u].size(); i++)
    {
        if (ch[u][i] != pre)
        {
            if (sz[ch[u][i]] % 2 == 0)
            {
                dfs(ch[u][i], u);
            }
        }
    }  

    printf("%d\n", u);  

    for (int i = 0; i < ch[u].size(); i++)
    {
        if (ch[u][i] != pre)
        {
            if (sz[ch[u][i]] % 2 == 1)
            {
                dfs(ch[u][i], u);
            }
        }
    }
}  

int main()
{  

    int N;
    scanf("%d", &N);
    int temp;
    int root;
    for (int i = 1; i <= N; i++)
    {
        scanf("%d", &temp);
        if (temp != 0)
        {
            ch[i].push_back(temp);
            ch[temp].push_back(i);
        }
        else
        {
            root = i;
        }
    }  

    if (N % 2 == 0)
    {
        printf("NO\n");
    }
    else
    {
        getsize(root,-1);
        printf("YES\n");
        dfs(root, -1);
    }  

    return 0;
}  

我wa的代码,原因是,我的写法是每次找出边是偶数的,删掉,再继续,仔细思考找到了可以把我wa的样例:

先删1的话,会导致输出“NO”

#include <iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<deque>
#include<vector>
#include<queue>
#define ll unsigned long long
#define inf 0x3f3f3f3f
using namespace std;
vector<int>v[200005];
bool us[200005];
int in[200005];
queue<int>q;
int main()
{
    int n;
    cin>>n;
    memset(us,0,sizeof(us));
    memset(in,0,sizeof(in));
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        if(x!=0)
        {
            v[x].push_back (i);
            v[i].push_back (x);
            in[i]++;
            in[x]++;
        }
    }
    if(n%2==0) cout<<"NO"<<endl;
    else
    {
        while(1)
        {
            int k=-1;
            for(int i=1;i<=n;i++)
            {
                if(!us[i]&&in[i]%2==0)
                {
                    k=i;
                    break;
                }
            }
            if(k==-1) break;
            q.push(k);
            us[k]=1;
            for(int j=0;j<v[k].size ();j++)
            {
                int y=v[k][j];
                if(us[y]) continue;
                in[y]--;
            }
        }
        bool f=1;
        for(int i=1;i<=n;i++)
        {
            if(!us[i])
            {
                f=0;
                break;
            }
        }
        if(!f) cout<<"NO";
        else
        {
            cout<<"YES"<<endl;
            while(!q.empty ())
            {
                cout<<q.front()<<endl;
                q.pop();
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/caiyishuai/p/9085779.html

时间: 2024-11-08 20:59:09

CodeForces - 963B Destruction of a Tree (dfs+思维题)的相关文章

Codeforces 963B Destruction of a Tree 【贪心】

本题的贪心策略是:每次删除连到叶子结点的dfs链上离根最远的偶数度的结点 greed is good 实现方法是先维护一个degree[i]表示第i个点有多少个度,然后dfs,当每一个结点的所有子节点被访问后准备返回时判断当前结点degree的奇偶性,如果是偶数就删除,是奇数就什么都不做.这样能保证你删除的结点[的子孙]度数都是奇数,及保证删除了[离根最远的偶数度的结点].每次删除要把它父亲和son的degree都减1,并且如果son的degree减完以后是偶数的话就把son也删除.(以为这样能

codeforces 682C Alyona and the Tree DFS

这个题就是在dfs的过程中记录到根的前缀和,以及前缀和的最小值 #include <cstdio> #include <iostream> #include <ctime> #include <vector> #include <cmath> #include <map> #include <stack> #include <queue> #include <algorithm> #include

Educational Codeforces Round 5 E. Sum of Remainders (思维题)

题目链接:http://codeforces.com/problemset/problem/616/E 题意很简单就不说了. 因为n % x = n - n / x * x 所以答案就等于 n * m - (n/1*1 + n/2*2 ... n/m*m) 在根号n复杂度枚举x,注意一点当m>n时,后面一段加起来就等于0,就不用再枚举了. 中间一段x1 ~ x2 的n/x可能相等,所以相等的一段等差数列求和. 1 //#pragma comment(linker, "/STACK:1024

Codeforces 1244F Chips(环修改,思维题)

链接:https://codeforces.com/contest/1244/problem/F 题意:给出一个每个节点黑色或者白色的环,k次更新,每次更新将所有满足条件的节点颜色反转(同时进行),满足条件:该节点的相邻的2个节点颜色和它不同.求k次后各个节点的颜色. 题解:环的话,序列复制向左右分别扩展一倍数,最后看中间部分,可以发现,颜色相同的连续的节点不会发生变化,颜色不同的序列,直接暴力更新即可,复杂度O(n) #include <bits/stdc++.h> #define IO_r

Codeforces 29D Ant on the Tree 树的遍历 dfs序

题目链接:点击打开链接 题意: 给定n个节点的树 1为根 则此时叶子节点已经确定 最后一行给出叶子节点的顺序 目标: 遍历树并输出路径,要求遍历叶子节点时按照给定叶子节点的先后顺序访问. 思路: 给每个节点加一个优先级. 把最后一个叶子节点到父节点的路径上的点优先级改为1 把倒数第二个叶子节点到父节点的路径上的点优先级改为2 如此每个点就有一个优先级,每个访问儿子节点时先访问优先级大的即可 对于无解的判断:得到的欧拉序列不满足输入的叶子节点顺序即是无解. #include <cstdio> #

CodeForces 29D Ant on the Tree

给一颗树,1为根,要求遍历树上所有点,给出叶子结点的访问顺序,限制每条边至多访问两次. 首先这是一棵树,那么两点之间的路线是确定的,所以我第一遍dfs预处理出从根节点到每个叶子的路径保存,以便后面输出. 那么就按照题目要求输出叶子结点的顺序依次输出,然后从一个叶子到下一个叶子的时候,从他们的最近公共祖先转折,所以我还预处理了相邻两个叶子结点的LCA. #include <iostream> #include <cstdlib> #include <cstring> #i

codeforces 220 C. Game on Tree

题目链接 codeforces 220 C. Game on Tree 题解 对于 1节点一定要选的 发现对于每个节点,被覆盖切选中其节点的概率为祖先个数分之一,也就是深度分之一 代码 #include<cstdio> #include<algorithm> const int maxn = 1000007; struct node { int u,v,next; } edge[maxn << 1] ; int head[maxn],num = 0; inline vo

Codeforces 6D Lizards and Basements 2 dfs+暴力

题目链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h> #include<queue> #include<string> #include<stdlib.h> #include<a

hdu6035[dfs+思维] 2017多校1

/*hdu6035[dfs+思维] 2017多校1*/ //合并色块, 妙啊妙啊 #include<bits/stdc++.h> using namespace std; const double eps=1e-8; const int inf=0x3f3f3f3f; typedef long long LL; vector<int>G[200005]; LL sum[200005]; int c[200005],son[200005],mark[200005]; int n,u,