首页 > 其他 > 详细

叶子的染色

时间:2019-11-11 22:18:55      阅读:92      评论:0      收藏:0      [点我收藏+]

https://loj.ac/problem/10161

题目描述

??有一个\(m\)个节点的树,可以选择一个度大于\(1\)的节点作为根,并将一些点染为白色或黑色,染色方案因保证根到每个叶子节点的路径上都至少有一个有色节点,并且路径上离叶子结点最近的节点颜色为\(c_i\)

思路

??我们考虑选哪个节点为根不影响答案的选择,因为我们只需要维护叶子节点上方最近的有颜色节点,非叶节点是否为根并不影响答案。我们考虑对于节点\(i\),如果要将\(i\)染成白色,显然它的叶子节点可以继承它的节点。我们记\(f[i][j]\)表示\(i\)染为\(j\)颜色的代价,而这个颜色是可以继承的。所以我们有两种选择,一是继承其父亲的颜色,二是设立一个新的颜色。继承的话这个点就无须设为应该设的颜色,所以转移方程为\(f[i][0]=\sum min\{f[v][0]-1,f[v][1]\}\)(\(v\)\(i\)的儿子)。黑色也类似,对于叶子节点将不符的颜色直接设为无穷大即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,INF=1e8;

int read()
{
    int res=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}
    return res*w;
}
void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}

int head[N],to[N<<1],nxt[N<<1],tot;
void add_edge(int x,int y)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
}
int f[N][3],n;
bool c[N];
void dfs(int u,int fa)
{
    if(u<=n)
    {
        f[u][c[u]]=1;
        f[u][(!c[u])]=INF;
        return ;
    }
    f[u][0]=f[u][1]=1;
    for(int i=head[u];i;i=nxt[i])
    {
        int v=to[i];
        if(v==fa)continue ;
        dfs(v,u);
        f[u][0]+=min(f[v][0]-1,f[v][1]);
        f[u][1]+=min(f[v][1]-1,f[v][0]);
    }
}

int main()
{
    int m;
    m=read(),n=read();
    for(int i=1;i<=n;i++)
        c[i]=read();
    for(int i=1;i<m;i++)
    {
        int x=read(),y=read();
        add_edge(x,y);add_edge(y,x);
    }   
    dfs(n+1,0);
    write(min(f[n+1][0],f[n+1][1]));
}

叶子的染色

原文:https://www.cnblogs.com/fangbozhen/p/11838765.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!