P3155 [CQOI2009]叶子的染色

P3155 [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,异色不变 即可

所以归纳一下, 无论如何, 我们在讨论的这个父节点总要在这一步染色, (在以后会不会把颜色撤销还不知道), 所以我们用两个数组 \(dp[i][2]\) 来表示第 \(i\) 号点分别染黑色、白色的最少用点数。 此时分类讨论, 有状态转移方程: \[dp[u][0] = 1 + \sum \min(dp[v][0] - 1,dp[v][1])\]\[dp[u][1] = 1 + \sum \min(dp[v][1] - 1,dp[v][0])\]

边界显然在叶子节点: 对于有需要的节点, 染成需要颜色则为 \(1\) ,不需要颜色赋值为无穷大以排除影响。 其他节点因为在动归本次时会加一个 \(1\) ,故不是叶子节点时自己加上 \(1\) 。

P.s. 当然我们需要判断一下此点的儿子是否有需要颜色, 若所有子节点都没有需要, 则将自己置为 \(0\) 这题数据较水加上偷点小懒, 这里就不特判啦

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int RD(){
    int flag = 1, out = 0;char c = getchar();
    while(c < '0' || c > '9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 1000019, INF = 1e9 + 19;
int head[maxn], nume = 1;
struct Node{
    int u, v, dis, nxt;
    }E[maxn << 3];
void add(int u, int v, int dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
int num, na;
int dp[maxn][2];
int root;
void dfs(int u, int F){
    bool flag = 0;
    for(int i = head[u];i;i = E[i].nxt){
        int v = E[i].v;
        if(v == F)continue;
        dfs(v, u);
        flag = 1;
        dp[u][0] += min(dp[v][0] - 1, dp[v][1]);
        dp[u][1] += min(dp[v][1] - 1, dp[v][0]);
        }
    if(flag)dp[u][0]++, dp[u][1]++;
    }
int main(){
    num = RD();na = RD();
    for(int i = 1;i <= na;i++){
        int x = RD();
        if(x == 0)dp[i][0] = 1, dp[i][1] = INF;
        else dp[i][0] = INF, dp[i][1] = 1;
        }
    for(int i = 1;i <= num - 1;i++){
        int u = RD(), v = RD();
        add(u, v, 1),add(v, u, 1);
        }
    root = na + 1;
    dfs(root, -1);
    int ans = min(dp[root][0], dp[root][1]);
    printf("%d\n", ans);
    return 0;
    }
    }

原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9337839.html

时间: 2024-12-13 15:02:46

P3155 [CQOI2009]叶子的染色的相关文章

BZOJ 1304: [CQOI2009]叶子的染色

1304: [CQOI2009]叶子的染色 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 566  Solved: 358[Submit][Status][Discuss] Description 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身). 对于每个叶结点u,定义c[u]为从根结

1304: [CQOI2009]叶子的染色 - BZOJ

Description给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身). 对于每个叶结点u,定义c[u]为从u到根结点的简单路径上最后一个(应该是最深的那个吧)有色结点的颜色.给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少.Input第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数.结点编号为1,2,-,m,

【bzoj1304】[CQOI2009]叶子的染色 树形dp

题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身). 对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色.给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少. 输入 第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数.结点编号为1,2,…,m,其中编号1,2,… ,n是叶子.以下

bzoj千题计划233:bzoj 1304: [CQOI2009]叶子的染色

http://www.lydsy.com/JudgeOnline/problem.php?id=1304 结论1:根节点一定染色 如果根节点没有染色,选择其子节点的一个颜色,那么所有这个颜色的子节点都不用染色.答案不会更差. 结论2:相邻节点不会染同一种颜色 将深度更大的那个有色节点变成无色仍然满足要求 结论3:任意一个非叶子节点做根,对答案都没有影响. 考虑将原根节点的一个自己点换成根,原来到根最近的颜色节点不变 所以,任取一个非叶子节点做根 dp[x][0/1]表示x染黑/白,使其子树内叶子

[CQOI2009]叶子的染色

https://www.zybuluo.com/ysner/note/1307594 题面 戳我 解析 一开始脑抽了,状态转移时默认直接在子结点染色... 其实这道题还是很简单的. 设\(dp[0/1/2][u]\)表示子树内的叶子结点还需要颜色\(0/1\),或都不需要颜色. 然后直接转移就对了. #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include

luogu 3155 [CQOI2009]叶子的染色

题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身). 对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色.给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少. 输入格式 第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数.结点编号为1,2,...,m,其中编号1,2,... ,n

[CQOI2009] 叶子的染色 - 树形dp

给一棵 \(m\) 个结点的无根树,你可以选择一个度数大于 \(1\) 的结点作为根,然后给一些结点着以黑色或白色.方案应保证根结点到每个叶子的简单路径上都至少包含一个有色结点. 对于每个叶结点 \(u\) ,定义 \(c[u]\) 为从根结点从 \(u\) 的简单路径上最后一个有色结点的颜色.给出每个 \(c[u]\) 的值,设计着色方案,使得着色结点的个数尽量少. Solution 选择任意一个点为根,答案都是相同的 随便选一个点为根,然后设 \(f[i][0/1]\) 表示将 \(i\)

bzoj1304: [CQOI2009]叶子的染色

又是一道优美的dp Description 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身). 对于每个叶结点u,定义c[u]为从根结点从U的简单路径上最后一个有色结点的颜色.给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少. Input 第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数.结点编号为1,2,…,

[luogu3155 CQOI2009] 叶子的染色(树形dp)

传送门 Solution 十分简单的树形dpQwQ,转移关系:父亲染了儿子不用染 只需要确定根就是简单树形dp,而其实根可以随便取一个非叶子节点 可以分情况讨论发现答案并不会改变 Code //By Menteur_Hxy #include <cmath> #include <vector> #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream&