【UOJ139】【UER #4】被删除的黑白树(贪心)

点此看题面

大致题意: 请你给一棵树黑白染色,使每一个叶结点到根节点的路径上黑节点个数相同。

贪心

显然,按照贪心的思想,我们要让叶结点到根节点的路径上黑节点的个数尽量大。

我们可以用\(Min_i\)来表示\(i\)的子树中深度最小的叶节点的深度。特殊的,若一个节点\(x\)为叶节点,则\(Min_x=dep_x\)

那叶结点到根节点的路径上黑节点的最大个数就是\(Min_1\)(显然)。

然后我们考虑把所有节点全部染黑,但这样极有可能不合法。

所以我们要把一些节点染回白色。

按照贪心的思想,我们应该尽可能选择深度小的节点将其染回白色,这样肯定是最优的。

具体实现详见代码。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define INF 1e9
#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,ee,ans,lnk[N+5],dep[N+5],Min[N+5];struct edge {int to,nxt;}e[N<<1];
class FastIO
{
    private:
        #define FS 100000
        #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
        #define pc(c) putchar(c)
        #define tn(x) (x<<3)+(x<<1)
        #define D isdigit(c=tc())
        int T,C;char c,*A,*B,FI[FS],FO[FS],S[FS];
    public:
        I FastIO() {A=B=FI;}
        Tp I void read(Ty& x) {x=0;W(!D);W(x=tn(x)+(c&15),D);}
        Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
        Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
void dfs1(CI x,CI lst)//第一遍DFS,求出Min数组
{
    for(RI i=(Min[x]=INF,lnk[x]);i;i=e[i].nxt) 
        e[i].to^lst&&(dep[e[i].to]=dep[x]+1,dfs1(e[i].to,x),Gmin(Min[x],Min[e[i].to]));//遍历子树,求出Min数组
    Min[x]==INF&&(Min[x]=dep[x]);//叶节点的Min为自身深度
}
void dfs2(CI x,CI lst,RI v)//第二遍DFS,求出答案
{
    Min[x]-Min[1]>v&&(++v,--ans);//如果当前节点需要染成白色,就将其染白,ans减1
    for(RI i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(dfs2(e[i].to,x,v),0);//遍历子树
}
int main()
{
    RI i,x,y;for(F.read(n),ans=n,i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);//连边,初始化将所有节点染黑(无需实际操作),赋ans=n
    return dfs1(1,0),dfs2(1,0,0),F.write(ans),0;//两遍DFS,输出答案
}

转载于:https://www.cnblogs.com/chenxiaoran666/p/UOJ139.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值