题目大意

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

题解

选什么根都一样

  证明思路是先证明一步,然后由此推广到所有可能。我们先证明:把一个根(以后简称“原根”)换为它的儿子(以后简称“新根”),最优情况不变。我们假定原根与新根的颜色要么不变要么交换。首先原根的、不以新根为根的子树内的叶子节点是不会受到影响的,因为它们到根的路径延长了,该遇到颜色的节点总会遇到的。那么以对于新根为子树内的叶子节点呢?如果原根与新根都有颜色,那么结果毫无影响,因为原根与新根的颜色肯定不相同(如果相同,把新根变为透明依然满足要求,结果却变小了),此时这个子树内不可能存在一个叶子节点,它到根节点路径上的第一个颜色为c[那个叶子]的结点(以后简称那个叶子“依赖”的结点)就是原根(因为经过了一个颜色不相同的结点新根)。唯一特殊的情况便是原根有颜色,新根是透明。换为新根后,依赖于原根的叶子结点便没有了依赖的对象了。怎么办?把原根与新根颜色交换就都满足要求了。

  综上所述,把现有的根换为当前根的儿子,结果不变。那么随便找另一个点作为根,那个点必然是当前根的儿子的儿子的儿子的儿子...,故答案也不变。所以,选什么根都一样。

动规

  树上求最值,往往要用树上DP。树上DP的子问题往往在子树中。问题在于:树与子树间的联系是什么?我们的思维可能会卡在我们的经验,也就是动规的子问题都是往往都是在局部将问题彻底解决。而这道题不一样,一个子树内的叶子结点所依赖的结点很有可能不在子树内。所以我们应当这样思考:当前问题的解决方案由子问题怎样改造而来的?

  我们先暂时用cur->DP来表示以cur为子树时,最少多少个结点需要染色。我们此时需要画一画。这时,我们发现在一个子问题中,根节点被染色的最优方案一定属于最优方案的集合中,因为任何根节点没有被染色的最优方案都可以通过将离根节点最近的染色结点的颜色转移到根节点上(以后简称“颜色转移根操作”)的方法转化为根节点被染色的最优方案。所以我们就令所有子问题的解根节点都被染色。当然如果只给一个DP问题不单纯,我们要将DP分为DP[0],DP[1]表示根节点染成黑色和染成白色时的最优解。首先要清楚一点,拿DP[0]为例,对于一个子树,如果我们要选择子树根为黑色的方案,因为cur就是黑色,所以在以cur为根的染色方案中,该子树根将要改为透明,故该子树内染色的节点数为cur->Son->DP[0]-1;如果要选择子树根为白色的方案,在以cur为根的方案中,该子树的染色方案不变,仍然为cur->Son->DP[1]。所以cur->DP[0]=1+sum(i){min{cur->Son[i]->DP[0]-1,cur->Son[i]->DP[1]}}。cur->DP[1]同理。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std; const int MAX_NODE = 10010, INF = 0x3f3f3f3f;
int TotLeaf, TotNode; struct Node
{
vector<Node*> Next;
int ColorWant;
int F[2];
}_nodes[MAX_NODE]; void Dfs(Node *cur, Node *fa)
{
if (cur - _nodes <= TotLeaf)
return;
cur->F[0] = cur->F[1] = 1;
for (int i = 0; i < cur->Next.size(); i++)
{
Node *next = cur->Next[i];
if(next == fa)
continue;
Dfs(next, cur);
cur->F[0] += min(next->F[0] - 1, next->F[1]);
cur->F[1] += min(next->F[1] - 1, next->F[0]);
}
} int main()
{
scanf("%d%d", &TotNode, &TotLeaf);
for (int i = 1; i <= TotLeaf; i++)
scanf("%d", &_nodes[i].ColorWant);
for (int i = 1; i <= TotLeaf; i++)
{
_nodes[i].F[_nodes[i].ColorWant] = 1;
_nodes[i].F[!_nodes[i].ColorWant] = INF;
}
for (int i = 1; i <= TotNode - 1; i++)
{
int u, v;
scanf("%d%d", &u, &v);
_nodes[u].Next.push_back(_nodes + v);
_nodes[v].Next.push_back(_nodes + u);
}
for (int i = TotLeaf + 1; i <= TotNode; i++)
_nodes[i].F[0] = _nodes[i].F[1] = 0;
Dfs(_nodes + TotLeaf + 1, NULL);
printf("%d\n", min(_nodes[TotLeaf + 1].F[0], _nodes[TotLeaf + 1].F[1]));
return 0;
}

  

luogu3155 [CQOI2009]叶子的染色的更多相关文章

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

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

  2. BZOJ 1304: [CQOI2009]叶子的染色

    1304: [CQOI2009]叶子的染色 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 566  Solved: 358[Submit][Statu ...

  3. 洛谷 P3155 [CQOI2009]叶子的染色 解题报告

    P3155 [CQOI2009]叶子的染色 题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到 ...

  4. 【BZOJ1304】[CQOI2009]叶子的染色(动态规划)

    [BZOJ1304][CQOI2009]叶子的染色(动态规划) 题面 BZOJ 洛谷 题解 很简单. 设\(f[i][0/1/2]\)表示以\(i\)为根的子树中,还有颜色为\(0/1/2\)(\(2 ...

  5. P3155 [CQOI2009]叶子的染色

    P3155 [CQOI2009]叶子的染色 题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到 ...

  6. BZOJ1304 CQOI2009 叶子的染色 【树形DP】

    BZOJ1304 CQOI2009 叶子的染色 Description 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方 ...

  7. BZOJ_1304_[CQOI2009]叶子的染色_树形DP

    BZOJ_1304_[CQOI2009]叶子的染色_树形DP Description 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白 ...

  8. CQOI2009叶子的染色

    叶子的染色 题目描述 给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根.内部结点和叶子均可)着以黑色或白色.你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一 ...

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1304 结论1:根节点一定染色 如果根节点没有染色,选择其子节点的一个颜色,那么所有这个颜色的子节点都 ...

随机推荐

  1. 【转】Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例

    概要 前一章,我们学习了HashMap.这一章,我们对Hashtable进行学习.我们先对Hashtable有个整体认识,然后再学习它的源码,最后再通过实例来学会使用Hashtable.第1部分 Ha ...

  2. [ POI 2011 ] Dynamite

    \(\\\) \(Description\) 一棵\(N\)个节点的树,树上有\(M\)个节点是关键点,选出\(K\)个特殊点,使得所有关键点到特殊点的距离中最大的最小,输出最大值最小为多少. \(N ...

  3. [ NOIP 1998 ] TG

    \(\\\) \(\#A\) 车站 火车从第\(1\)站开出,上车的人数为\(a\),然后到达第\(2\)站,在第\(2\)站有人上.下车,但上.下车的人数相同,因此在第\(2\)站开出时(即在到达第 ...

  4. Android项目实战_手机安全卫士程序锁

    ###1.两个页面切换的实现1. 可以使用Fragment,调用FragmentTransaction的hide和show方法2. 可以使用两个布局,设置visibility的VISIABLE和INV ...

  5. html5——全屏显示

    基本概念 1.HTML5规范允许用户自定义网页上任一元素全屏显示 2.requestFullscreen() 开启全屏显示.cancleFullscreen() 关闭全屏显示 3.不同浏览器兼容性不一 ...

  6. 【译】x86程序员手册09-第3章程序指令集

    注:觉得本章内容与理解操作系统不直接相关,所以本章并未看完,也就没有翻译完,放在这里中是为了保证手册的完整.有兴趣的人可以去原址查看. https://pdos.csail.mit.edu/6.828 ...

  7. Lvs Keepalive DR模式高可用配置

    Lvs Keepalive DR模式配置 一.环境 #DIP# eth0:192.168.233.145#VIP# eth0:0 192.168.233.250/32 #RIP1:192.168.23 ...

  8. UIResponder详解

    UIResponder Class Reference Managing the Responder Chain 1.- (UIResponder *)nextResponder 返回接收者的下一个相 ...

  9. Origin C调用NAG库

    NAG(Numerical Algorithms Group, www.nag.com)库是一个无与伦比的算法库,它提供的算法可靠.轻便.严谨,覆盖了数学与统计方方面面.最大的缺点就是:它是一个收费的 ...

  10. Linux快速入门教程-进程管理ipcs命令学习

    使用Linux系统必备的技能之一就是Linux进程管理,系统运行的过程正是无数进程在运行的过程.这些进程的运行需要占用系统的内存等资源,做好系统进程的管理,对于我们合理分配.使用系统资源有非常大的意义 ...