题目大意

  给一棵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. 初学layer

    canvas是支持图层layer渲染这种技术的,canvas默认就有一个layer,当我们平时调用canvas的各种drawXXX()方法时,其实是把所有的东西都绘制到canvas这个默认的layer ...

  2. jQuery怎么去掉标签的hover效果

    今天项目中遇到jquery去掉hover效果的问题,开始以为直接unbind(“hover”)就可以搞定,可是实际验证这个方法并没有作用,正确的使用方法应该是下面这样: /* 这种方法是新增的,在老的 ...

  3. iOS开发中如何实现同步、异步、GET、POST等请求实操演示!

    1.同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可以进行下一步操作, 2.异步请求不会阻塞主线程,而会建立一个新的线程来操作,用户发出异步请求后,依然 ...

  4. php判断form数据是否为POST而来,判断数据提交方式

    //判断form数据是否为POST而来,判断数据提交方式 if ($_SERVER['REQUEST_METHOD'] != 'POST') { // 非 POST 来路,做警告或你想做的事 retu ...

  5. 实例分割:MaskXRCnn 与Visual Genome数据集

    一.VG数据集 机器学习领域的突破突然让计算机获得了以未曾有的高精度识别图像中物体的能力--几乎达到了让人惊恐的程度.现在的问题是机器是否还能更上层楼,学会理解这些图片中所发生的事件. Visual ...

  6. Java中接口与接口和类之间的关系

    接口和接口之间的关系 继承关系 可以多继承,并且可以多层继承 注意: 1.如果多个父接口中有同名的抽象方法,那么子接口只需要实现一次即可 2.如果多个父接口中有同名的默认方法,那么子接口必须重写默认方 ...

  7. CAD向控件注册一个命令(com接口VB语言)

    主要用到函数说明: MxDrawXCustomFunction::Mx_RegistUserCustomCommand 向控件注册一个命令,用户在命令行输入命令名这个字符串,就会触发执行命令事件 命令 ...

  8. parseInt()函数

    parseInt()转化整形是从左往右,取出第一个整型,如:10a10b,则显示10: //20170719补充 如果该字符串第一个字符是0,那么该字符串会基于八进制而非十进制来求值,在八进制中,8和 ...

  9. unzip 命令巧用举例

    1.把文件解压到当前目录下 unzip master.zip 2.如果要把文件解压到指定的目录下,需要用到-d参数. unzip -d /tmp master.zip 3.解压的时候,有时候不想覆盖已 ...

  10. js 简单小知识

    1. javascript的typeof返回哪些数据类型: string, boolean, number, undefined, function, object 2. split() join() ...