Codeforces 963B Destruction of a Tree(dfs)

题目链接:Destruction of a Tree

题意

给定一个 n n 个节点的树,每次可以从树上选择一个度为偶数的节点进行删除,每删除一个节点,与这个节点相连的所有边都被删除,问能否删除整棵树。

输入

第一行为一个整数 n (1n2×105),第二行为 n n 个整数 p1,p2,,pn (0pin),如果 pi0 p i ≠ 0 ,表示节点 pi p i i i 之间有一条连边,数据保证给定的结构是一棵树。

输出

如果无法删除整棵树,输出 NO,否则在第一行输出 YES Y E S ,接下去 n n 行输出 n 个整数,表示删除节点的顺序。

样例

输入
5
0 1 2 1 2
输出
YES
1
2
3
5
4
提示
删点过程如下:

输入
4
0 1 2 3
输出
NO
题解

从叶子节点往树根 dfs d f s ,只要发现某个节点的度为偶数,就立即删除这个节点并往下 dfs d f s ,最后注意剪枝。

过题代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <functional>
#include <algorithm>
using namespace std;

#define LL long long
const int maxn = 200000 + 100;
int n, p, cnt;
int ans[maxn], deg[maxn];
bool vis[maxn];
vector<int> G[maxn];
queue<int> que;

void dfs(int f, int x, bool flag) {
    int len = G[x].size();
    if(!flag) {
        for(int i = 0; i < len; ++i) {
            int pos = G[x][i];
            if(!vis[pos] && pos != f) {
                dfs(x, pos, false);
            }
        }
    }
    if(deg[x] % 2 == 0) {
        deg[x] = 0;
        ans[cnt++] = x;
        vis[x] = true;
        for(int i = 0; i < len; ++i) {
            int pos = G[x][i];
            if(!vis[pos]) {
                --deg[pos];
                if(pos != f) {
                    dfs(x, pos, true);
                }
            }
        }
    }
}

int main() {
    #ifdef LOCAL
    freopen("test.txt", "r", stdin);
    #endif // LOCAL

    while(scanf("%d", &n) != EOF) {
        cnt = 0;
        for(int i = 1; i <= n; ++i) {
            G[i].clear();
            deg[i] = 0;
            vis[i] = false;
        }
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &p);
            if(p != 0) {
                G[i].push_back(p);
                G[p].push_back(i);
                ++deg[i];
                ++deg[p];
            }
        }
        dfs(1, 1, false);
        if(cnt != n) {
            printf("NO\n");
            continue;
        }
        printf("YES\n");
        for(int i = 0; i < cnt; ++i) {
            printf("%d\n", ans[i]);
        }
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值