叶子的颜色

 

试题描述

    给一棵有 m 个节点的无根树,你可以选择一个度数大于 1 的节点作为根,然后给一些节点(根、内部节点、叶子均可)着以黑色或白色。你的着色方案应保证根节点到各叶子节点的简单路径上都包含一个有色节点,哪怕是叶子本身。对于每个叶子节点 u,定义 cu 为从根节点到 u 的简单路径上最后一个有色节点的颜色。给出每个 cu​  的值,设计着色方案使得着色节点的个数尽量少。

输入
第一行包括两个数 m 和 n,依次表示节点总数和叶子个数,节点编号依次为 1 至 m。接下来 n 行每行一个 0 或 1 的数,其中 0 表示黑色,1 表示白色,依次为 c1,c2,⋯,cn。接下来 m−1 行每行两个整数 a,b,表示节点 a 与 b 有边相连。
输出
输出仅一个数,表示着色节点数的最小值。
输入示例
5 3
0
1
0
1 4
2 5
4 5
3 5
输出示例
2
其他说明
数据 1 2 3 4 5 6 7 8 9 10
M 10 50 100 200 400 1000 4000 8000 10000 10000
N 5 23 50 98 197 498 2044 4004 5021 4996

 看注释

#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
inline int rd()
{
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
inline void write(int x)
{
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int head[100006],to[100006],nxt[100006];
int total=0;
int m,n;
void add(int x,int y)
{
    total++;
    to[total]=y;
    nxt[total]=head[x];
    head[x]=total;
    return ;
}
int book[100006];
int f[100006][3];
void dfs(int x,int la)
{
    f[x][1]=f[x][0]=1;//注意:0不是无色 
    if(book[x]!=-1) f[x][!book[x]]=2147483646;//如果一个点已经染色,那么就不可能染成别的颜色 
    for(int e=head[x];e;e=nxt[e])
    {
        int h=to[e];
        if(h!=la)
        {
            dfs(h,x);
            f[x][1]+=min(f[h][0],f[h][1]-1);//如果已经染了一个颜色,子树就不用染同一个颜色,所以可以-1 
            f[x][0]+=min(f[h][1],f[h][0]-1);
        }
    }
    return ;
}
int main()
{
    //还是树形DP裸题,看不出来还是不要写了 
    memset(book,-1,sizeof(book));
    m=rd();
    n=rd();
    for(int i=1;i<=n;i++) book[i]=rd();//读入每个染色节点的颜色 
    for(int i=1;i<m;i++)
    {
        int x,y;
        x=rd();
        y=rd();
        add(x,y);
        add(y,x);//双向存边 
    }
    dfs(n+1,0);//直接从n+1开始,之前还傻傻的跑了一个root 
    printf("%d",min(f[n+1][0],f[n+1][1]));
    return 0;
}

最后喜欢的话不如来推荐,评论,关注三连。

不喜欢的话也昧着良心推荐一下吧!!!!

转载于:https://www.cnblogs.com/WWHHTT/p/9505070.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值