zoukankan      html  css  js  c++  java
  • 【uoj#139】[UER #4]被删除的黑白树 贪心

    题目描述

    给出一个 $n$ 个节点的树,$1$ 号点为根。现要将其中一些点染成黑色,使得每个叶子节点(不包括根节点)到根节点路径上的黑点数相同。求最多能够染多少个黑点。


    题解

    贪心

    显然有结论:选择的黑点尽量靠近叶子节点。

    并且显然每个点到根节点路径上的黑点数是:深度最小的叶子节点到根节点路径上的点数。

    那么首先预处理出每个点子树内深度最小的叶子节点的深度,然后进行贪心过程:显然如果一个点染黑,那么它到其子树内深度最小的叶子节点路径上的所有点都要染黑。我们维护每个点到根节点的路径上染了多少黑点,就能根据已经染黑的节点数和它到其字数内深度最小的叶子节点路径上的点数即可判断出当前点是否能够选择。

    时间复杂度 $O(n)$

    #include <cstdio>
    #include <algorithm>
    #define N 100010
    using namespace std;
    int head[N] , to[N << 1] , next[N << 1] , cnt , deep[N] , md[N] , now[N] , ans;
    inline void add(int x , int y)
    {
    	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
    }
    void dfs(int x , int fa)
    {
    	int i;
    	if(x != 1 && !next[head[x]]) md[x] = deep[x];
    	else md[x] = 1 << 30;
    	for(i = head[x] ; i ; i = next[i])
    		if(to[i] != fa)
    			deep[to[i]] = deep[x] + 1 , dfs(to[i] , x) , md[x] = min(md[x] , md[to[i]]);
    }
    void solve(int x , int fa)
    {
    	int i;
    	now[x] = now[fa];
    	if(now[fa] + md[x] - deep[x] == md[1]) now[x] ++ , ans ++ ;
    	for(i = head[x] ; i ; i = next[i])
    		if(to[i] != fa)
    			solve(to[i] , x);
    }
    int main()
    {
    	int n , i , x , y;
    	scanf("%d" , &n);
    	for(i = 1 ; i < n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
    	dfs(1 , 0);
    	solve(1 , 0);
    	printf("%d
    " , ans);
    	return 0;
    }
    
  • 相关阅读:
    2019-8-31-C#-性能分析-反射-VS-配置文件-VS-预编译
    2018-8-10-WPF-鼠标移动到列表上-显示列表图标
    C语言对齐、补齐
    main函数前后
    Ubuntu安装telnet
    Ubuntu安装rpm
    extern c 解释
    gcc和g++编译器
    原子操作
    linux内核信号量
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8244237.html
Copyright © 2011-2022 走看看