zoukankan      html  css  js  c++  java
  • [CQOI2009]叶子的染色

    题目描述

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

    输入输出格式

    输入格式:

    第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,...,m,其中编号1,2,... ,n是叶子。以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],...,c[n]。以下m-1行每行两个整数a,b(1<=a < b <= m),表示结点a和b 有边相连。

    输出格式:

    仅一个数,即着色结点数的最小值。

    输入输出样例

    输入样例#1:
    5 3
    0
    1
    0
    1 4
    2 5
    4 5
    3 5
    输出样例#1:
    2

    说明

    M<=10000

    N<=5021

    解析:

    树形dp

    选择一个不是叶子节点的点做跟来遍历整棵树

    dp[i][j]用来表示当前我们在i这个节点,当前这个节点染成j色的时候,子树染色需要的最小值

    然后怎么转移呢,就是当他的子节点要有和他染成相同颜色的,就可以染到当前的点,他的子树如果染别的颜色的

    个数就统计在自己身上

    代码:

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #define MAXN 10010
    using namespace std;
    
    struct Edge{
        int vi;
        int vj;
        int next;
    }edge[1001011];
    
    int head[MAXN];
    int now = 0;
    
    int rudu[MAXN];
    int c[MAXN];
    
    int dp[MAXN][2];
    
    void dfs(int now,int fa)
    {
        if(rudu[now] == 1)
        {
            dp[now][c[now]] = 1;
            dp[now][c[now]^1] = 0x7ffffff;
            return;
        }
        dp[now][1] = dp[now][0] = 1;
        for(int i = head[now];i;i = edge[i].next)
        {
            int vj = edge[i].vj;
            if(vj == fa)continue;
            
            dfs(vj,now);
            dp[now][1] += min(dp[vj][1] - 1,dp[vj][0]);
            dp[now][0] += min(dp[vj][1],dp[vj][0] - 1); 
        }
    }
    
    void push(int vi,int vj)
    {
        now++;
        edge[now].vi = vi;
        edge[now].vj = vj;
        edge[now].next = head[vi];
        head[vi] = now;
    }
    
    int main()
    {
        int n,m;
        scanf("%d%d",&m,&n);
        
        for(int i = 1;i <= n;i++)
        {
            scanf("%d",&c[i]);
        }
        
        for(int i = 1;i < m;i++)
        {
            int vi,vj;
            scanf("%d%d",&vi,&vj);
            push(vi,vj);
            push(vj,vi);
            rudu[vi]++;
            rudu[vj]++;
        }
        rudu[m]++;
        dfs(m,0);
        
        printf("%d",min(dp[m][0],dp[m][1]));
        
        return 0;
    }
  • 相关阅读:
    揭示同步块索引(下):总结
    关于.NET技术体系的思维导图
    嵌入式Linux中摄像头使用简要整理
    Tslib和Qt 4.8.4与在开发板上的移植
    图像处理经典图片Lena背后的故事
    Linux 下编译安装OpenCV
    Linux 下编译、安装、配置 QT
    Qt Creator的配置和开发初步测试
    OpenCV的第一个小程序:读取图像并显示
    转:智能手机Flash/DRAM选择、配置与价格大全
  • 原文地址:https://www.cnblogs.com/luoyibujue/p/7658418.html
Copyright © 2011-2022 走看看