luogu 3155 [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[节点][0/1]

如果节点v不染色,就是dp[v][0/1] - 1

如果根的颜色与儿子一样,那么儿子就不用涂色,如果不一样,儿子就涂色

转移方程:

关于初值:对于不是叶节点的点,初值为1,

而叶节点,如果与他所需的颜色符合,便赋为1,不同则赋为2(或极大值)

看转移方程,如果叶节点染的颜色与自身所需不同,那么当父节点的颜色也与自身所需不同,这个节点就必须染回来,那么他对答案的贡献为

dp[v][与所需不同] - 1 = 1;

如果当父节点的颜色也与自身所需相同,那么它不染色最好,赋为2的那一个状态对答案无影响

其实我觉得赋成极大值表示这种情况不能选也是可以的

好了,这是根固定的情况

如果根不固定?

换根,其实就是将旧根到新根的路径上的节点的父子关系颠倒一下,其余节点都不变

颠倒父子关系对答案有什么影响吗?

没有影响

因为儿子如果有颜色,就可以屏蔽父亲的颜色

就算从方程来看,也就是将生成答案的几项调换了一下顺序,答案是不变的

代码

 1 /*********************
 2 User:Mandy.H.Y
 3 Language:c++
 4 Problem:luogu3155
 5 Algorithm:
 6 *********************/
 7 #include<bits/stdc++.h>
 8
 9 using namespace std;
10
11 const int maxn = 5050;
12 const int maxm = 10005;
13
14 int n,m,size;
15 int first[maxm];
16 bool c[maxn];
17 int dp[maxm][5];
18
19 struct Edge{
20     int v,nt;
21 }edge[maxm<<1];
22
23 template<class T>inline void read(T &x){
24     x = 0;bool flag = 0;char ch = getchar();
25     while(!isdigit(ch)) flag |= ch == ‘-‘,ch = getchar();
26     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
27     if(flag) x = -x;
28 }
29
30 template<class T>void putch(const T x){
31     if(x > 9) putch(x / 10);
32     putchar(x % 10 | 48);
33 }
34
35 template<class T>void put(const T x){
36     if(x < 0) putchar(‘-‘),putch(-x);
37     else putch(x);
38 }
39
40 void file(){
41     freopen("3155.in","r",stdin);
42 //    freopen("3155.out","w",stdout);
43 }
44
45 void eadd(int u,int v){
46     edge[++size].v = v;
47     edge[size].nt = first[u];
48     first[u] = size;
49 }
50
51 void readdata(){
52     read(m);read(n);
53     for(int i = 1;i <= n; ++ i) read(c[i]);
54     for(int i = 1; i<m; ++ i){
55         int u,v;
56         read(u);read(v);
57         eadd(u,v);eadd(v,u);
58     }
59 }
60
61 void dfs(int u,int fa){
62     if(u > n) dp[u][1] = dp[u][0] = 1;
63     else dp[u][c[u]] = 1,dp[u][c[u]^1] = 2;
64     for(int i = first[u];i;i = edge[i].nt){
65         int v = edge[i].v;
66         if(v == fa) continue;
67         dfs(v,u);
68         dp[u][0] += min(dp[v][0]-1,dp[v][1]);
69         dp[u][1] += min(dp[v][1]-1,dp[v][0]);
70     }
71 }
72
73 void work(){
74     dfs(n+1,0);
75     put(min(dp[n+1][0],dp[n+1][1]));
76 }
77
78 int main(){
79 //    file();
80     readdata();
81     work();
82     return  0;
83 }

原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11494327.html

时间: 2024-07-30 07:37:36

luogu 3155 [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,

P3155 [CQOI2009]叶子的染色

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

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

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

【Luogu】P3155叶子的染色(树形DP)

题目链接 树形DP水题qwq. 设f[i][j]是以i为根的子树,染成j色,且满足内部需求的最少染色节点数. 设to是x的子节点,那么状态转移方程如此设计: 1.f[i][0] 这个状态表示i不染色,那显然很好办,对于每个to从f[to][1],f[to][2]和f[to][0]里选一个最小的即可. 转移方程$f[x][0]=\sum\limits_{to}min(f[to][1],f[to][2],f[to][0])$ 2.f[i][1] 此时i染成黑色.那么对于每个to我们发现,既可以让它继

bzoj1304: [CQOI2009]叶子的染色

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