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

题目描述

给一棵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 有边相连。

输出

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

样例输入

5 3
0
1
0
1 4
2 5
4 5
3 5

样例输出

2



题解

树形dp

考虑如果给定根节点的话怎么做:

设 $f[i][j]$ 表示以 $i$ 为根的子树,$i$ 到根节点的简单路径上最后一个有色节点的颜色是 $j$ 的最小着色点数。

那么对于所有 $i$ 的儿子 $k$ ,有 $f[i][j]+=min(f[k][j],f[k][j\text{^}1])$ 。边界条件 $f[u][c[u]]=0,f[u][c[u]\text{^}1]=\infty$ ,其中 $u$ 是叶子节点。

那么 $min(f[root][0],f[root][1])+1$ 就是 $root$ 作为树根时的答案,其中 $+1$ 指的是根节点需要再着色一次。

一次dp的时间复杂度是 $O(n)$ ,我们可以枚举每个节点为根,复杂度为 $O(n^2)$ ,可过。

但是还有更优的做法:考虑根节点从 $x$ 变化到相邻的点 $y$ 的过程,那么 $x$ 为根时,$y$ 的着色只有两种情况:染了与 $x$ 不同的颜色、没有染色。

第一种情况显然换根后方案可以不变,第二种情况显然可以换根时把 $x$ 的着色该为染 $y$ ,答案不变。因此有 $ans_y\le ans_x$,同时从 $y$ 换到 $x$ 时有 $ans_x\le ans_y$ ,所以 $ans_x=ans_y$。

于是选择任意一个非叶节点作为根做一次dp即可,时间复杂度 $O(n)$

#include <cstdio>
#include <algorithm>
#define N 10010
using namespace std;
int head[N] , to[N << 1] , next[N << 1] , cnt , f[N][2];
inline void add(int x , int y)
{
	to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x , int fa)
{
	int i;
	for(i = head[x] ; i ; i = next[i])
		if(to[i] != fa)
			dfs(to[i] , x) , f[x][0] += min(f[to[i]][0] , f[to[i]][1] + 1) , f[x][1] += min(f[to[i]][1] , f[to[i]][0] + 1);
}
int main()
{
	int n , m , i , x , y;
	scanf("%d%d" , &m , &n);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &x) , f[i][x] = 0 , f[i][x ^ 1] = m;
	for(i = 1 ; i < m ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x);
	dfs(m , 0);
	printf("%d\n" , min(f[m][0] , f[m][1]) + 1);
	return 0;
}
时间: 2024-09-29 08:45:08

【bzoj1304】[CQOI2009]叶子的染色 树形dp的相关文章

[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,…,

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]为从根结

P3155 [CQOI2009]叶子的染色

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

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

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

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

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

luogu 3155 [CQOI2009]叶子的染色

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

【BZOJ4033】[HAOI2015]树上染色 树形DP

[BZOJ4033][HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益.问收益最大值是多少. Input 第一行两个整数N,K. 接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to). 输入保证所有点之间是联通的. N<=2000,0<=K&l

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

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