bzoj1304: [CQOI2009]叶子的染色

又是一道优美的dp

Description

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

Input

第一行包含两个正整数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 有边相连。

Output

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

Sample Input

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

Sample Output

2

HINT

M<=10000

N<=5021


题目分析

这题的限制有些诡异,并且长得非常不像dp。仿佛我们需要三个状态$f[i][0/1/2]$来表示当前涂色状态,而且这样转移起来甚是麻烦。

但是细细一想,若一个点$node$有众多子节点,那就意味着有众多的叶子节点。而每一个叶子节点都是要上色的,况且上的色非黑即白就两种。

那么不论$node$子树内白多黑多,$node$这个节点当然要承担起父节点的责任,涂成一种颜色,这样肯定是不会更差的。

于是只有两个状态的树形dp就不难想到也不难打出了。

 1 /**************************************************************
 2     Problem: 1304
 3     User: AntiQuality
 4     Language: C++
 5     Result: Accepted
 6     Time:20 ms
 7     Memory:1600 kb
 8 ****************************************************************/
 9  
10 #include<bits/stdc++.h>
11 const int maxn = 10035;
12 const int INF = 2e9;
13  
14 int n,m,c[maxn];
15 int f[maxn][2];
16 int edgeTot,edges[maxn<<1],nxt[maxn<<1],head[maxn];
17  
18 int read()
19 {
20     char ch = getchar();
21     int num = 0;
22     bool fl = 0;
23     for (; !isdigit(ch); ch = getchar())
24         if (ch==‘-‘) fl = 1;
25     for (; isdigit(ch); ch = getchar())
26         num = (num<<1)+(num<<3)+ch-48;
27     if (fl) num = -num;
28     return num;
29 }
30 void addedge(int u, int v)
31 {
32     edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot;
33     edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
34 }
35 void dp(int now, int fa)
36 {
37     if (now <= n){
38         f[now][c[now]] = 1, f[now][1-c[now]] = INF;
39         return;
40     }
41     f[now][0] = 1, f[now][1] = 1;
42     for (int i=head[now]; i!=-1; i=nxt[i])
43     {
44         int v = edges[i];
45         if (v!=fa){
46             dp(v, now);
47             f[now][0] += std::min(f[v][1], f[v][0]-1);  //可能这里为什么f[v][1]不加1,而是f[v][0]减1会有点疑问
48             f[now][1] += std::min(f[v][0], f[v][1]-1);  //f[now][]=1是每次dp时先确定好了的,这样可以避免重复计算
49         }                             //手推一下就好了
50     }
51 }
52 int main()
53 {
54     memset(head, -1, sizeof head);
55     m = read(), n = read();
56     for (int i=1; i<=n; i++) c[i] = read();
57     for (int i=1; i<m; i++) addedge(read(), read());
58     dp(m, 0);
59     printf("%d\n",std::min(f[m][0], f[m][1]));
60     return 0;
61 }

END

原文地址:https://www.cnblogs.com/antiquality/p/9255437.html

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

bzoj1304: [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

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\)

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

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