Codeforces 963B Destruction of a Tree 【贪心】

本题的贪心策略是:每次删除连到叶子结点的dfs链上离根最远的偶数度的结点

greed is good

实现方法是先维护一个degree[i]表示第i个点有多少个度,然后dfs,当每一个结点的所有子节点被访问后准备返回时判断当前结点degree的奇偶性,如果是偶数就删除,是奇数就什么都不做。这样能保证你删除的结点【的子孙】度数都是奇数,及保证删除了【离根最远的偶数度的结点】。每次删除要把它父亲和son的degree都减1,并且如果son的degree减完以后是偶数的话就把son也删除。(以为这样能保证该son是这条链上离root的最远节点,及该son的子孙度数都一定是奇数)注意如果parent的degree减完是偶数的话我们不能删掉parent,因为parent的所有子结点没有访问完,我们无法确定parent是不是离根最远的偶数度结点。

 1 #include<iostream>
 2 #include<vector>
 3 #define MAXN 200000
 4 using namespace std;
 5
 6 int n;
 7 int ans[MAXN+5],root,vis[MAXN+5],del[MAXN+5];
 8 int degree[MAXN+5],parent[MAXN+5];//第i个节点有多少度 ,每个节点的parent
 9 vector<int> edge[MAXN+5];
10 int top;
11 //从下往上删偶数度的点
12
13 void Del(int node){//删除node点,并且递归删除新的可删除的点
14     ans[++top]=node;
15     del[node]=1;//把当前node删掉
16     for(int i=0;i<edge[node].size();i++){
17         int v=edge[node][i];
18         if( del[v] ) continue;
19         degree[v]-=1;//一个结点被删除后只会影响他 parent和son的degree
20         if(degree[v]%2==0 && parent[node]!=v) Del(v);//不能删他的父亲结点,因为不知道父亲节点是不是离根最远的偶数度结点;
21                                                         //但如果是son的话可以保证,因为该节点后代的度数都是基数
22     }
23 }
24
25 void dfs(int node){
26     vis[node]=1;
27
28     for(int i=0;i<edge[node].size();i++){
29         int v=edge[node][i];
30         if(vis[v]) continue;
31         parent[v]=node;
32         dfs(v);
33     }
34
35     if(degree[node]%2==0) Del(node); //如果偶数度那删掉
36
37 }
38
39 int main(){
40
41 cin>>n;
42 for(int i=1;i<=n;i++) {
43     int v; cin>>v;
44     if(v==0) root=i;
45     else{
46         edge[i].push_back(v);
47         edge[v].push_back(i);
48     }
49 }
50
51 for(int i=1;i<=n;i++) degree[i]=edge[i].size();
52 dfs(root);
53
54 if( top==n ){
55     cout<<"YES"<<endl;
56     for(int i=1;i<=n;i++) cout<<ans[i]<<endl;
57 }
58 else cout<<"NO";
59
60
61
62     return 0;
63 }

原文地址:https://www.cnblogs.com/ZhenghangHu/p/8973587.html

时间: 2024-08-30 17:42:41

Codeforces 963B Destruction of a Tree 【贪心】的相关文章

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 ot

[Codeforces 1295E]Permutation Separation(线段树+贪心)

[Codeforces 1295E]Permutation Separation(线段树+贪心) 题面 给出一个排列\(p_1,p_2,...p_n\).初始时你需要选择一个位置把排列分成左右两个.然后在两个序列间移动元素使得左边序列的所有元素都比右边的所有元素小.给出每个元素\(p_i\)从一个序列移动到另一个序列的代价\(a_i\). 分析 显然最后得到的序列是小的数在一边,大的数在另一边.设从值为\(i\)的元素处分开之后移动代价为\(ans_i\). 一开始假设所有数都移到右边序列,那么

Codeforces 583 DIV2 Robot&#39;s Task 贪心

原题链接:http://codeforces.com/problemset/problem/583/B 题意: 就..要打开一个电脑,必须至少先打开其他若干电脑,每次转向有个花费,让你设计一个序列,使得总花费最小. 题解: 就傻傻的走就好..从左走到右,再走回来,更新序列和答案就好. 代码: #include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #define MA

Codeforces 442C Artem and Array(stack+贪心)

题目连接:Codeforces 442C Artem and Array 题目大意:给出一个数组,每次删除一个数,删除一个数的得分为两边数的最小值,如果左右有一边不存在则算作0分.问最大得分是多少. 解题思路:首先将连续的a,b,c,a > b && c > b的情况将c掉,获得min(a,b)分,这样处理后数组变成一个递増再递减的序列,除了最大和第二大的取不到,其他数字均可以得分. 样例:4 10 2 2 8 #include <cstdio> #include

Codeforces 18D Seller Bob java大数+贪心

题目链接:点击打开链接 java: import java.math.BigInteger; import java.util.Scanner; public class Main { static int N = 5005; static BigInteger[] er = new BigInteger[N]; static BigInteger E = new BigInteger("2"); static int[] a = new int[N]; static int[] ma

Codeforces 437C The Child and Toy(贪心)

题目连接:Codeforces 437C The Child and Toy 题目大意:孩子有一个玩具,有n个部件组成,m条绳子组成,每条绳子连接两个部件.小孩比较顽皮,要将玩具拆成不可分割的部件,每次剪断一条绳子的代价是该绳子连接的两个部件的权值中较小的值.问说最小的总代价是多少. 解题思路:以为每条边都是要被剪断的,所以将节点按照代价值从大到小排序,每次拿掉权值大的点,与该点连接并且还未剪断的边均用另外点的权值. #include <cstdio> #include <cstring

Codeforces 437D The Child and Zoo(贪心+并查集)

题目链接:Codeforces 437D The Child and Zoo 题目大意:小孩子去参观动物园,动物园分很多个区,每个区有若干种动物,拥有的动物种数作为该区的权值.然后有m条路,每条路的权值为该条路连接的两个区中权值较小的一个.如果两个区没有直接连接,那么f值即为从一个区走到另一个区中所经过的路中权值最小的值做为权值.问,平均两个区之间移动的权值为多少. 解题思路:并查集+贪心.将所有的边按照权值排序,从最大的开始连接,每次连接时计算的次数为连接两块的节点数的积(乘法原理). #in

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

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

Codeforces 459E Pashmak and Graph(dp+贪心)

题目链接:Codeforces 459E Pashmak and Graph 题目大意:给定一张有向图,每条边有它的权值,要求选定一条路线,保证所经过的边权值严格递增,输出最长路径. 解题思路:将边按照权值排序,每次将相同权值的边同时加入,维护每个点作为终止点的最大长度即可. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 3