题目大意

  给一棵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. activiti 表——介绍

    Activiti 用到的表都是act_开头 下面分别来介绍下 activiti 所用到的表: Act_RE_* 表示 RepositoryService接口所操作的表:包含了流程定义信息 .流程静态资 ...

  2. css3通过scale()实现放大功能、通过rotate()实现旋转功能

    css3通过scale()实现放大功能.通过rotate()实现旋转功能,下面有个示例,大家可以参考下 通过scale()实现放大功能 通过rotate()实现旋转功能 而transition则可设置 ...

  3. mybatis中映射文件和实体类的关联性

    mybatis的映射文件写法多种多样,不同的写法和用法,在实际开发过程中所消耗的开发时间.维护时间有很大差别,今天我就把我认为比较简单的一种映射文件写法记录下来,供大家修改建议,争取找到一个最优写法~ ...

  4. Caffe FCN:可视化featureMaps和Weights(C++)、获取FCN结果

    为何不使用C++版本FCN获取最后的分割掩模,何必要使用python呢!因此需要获取网络最后层的featureMaps,featureMaps的结果直接对应了segmentation的最终结果,可以直 ...

  5. MSSQL高并发下生成连续不重复的订单号

    一.确定需求 只要做过开发的基本上都有做过订单,只要做过订单的基本上都要涉及生成订单号,可能项目订单号生成规则都不一样,但是大多数规则都是连续增长. 所以假如给你一个这样的需求,在高并发下,以天为单位 ...

  6. django-Celery分布式队列简单使用

    介绍: Celery 是一个简单.灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具. 它是一个专注于实时处理的任务队列,同时也支持任务调度. worker:是一个独立的进程, ...

  7. flask之配置文件的加载和动态url的使用

    七行代码实现一个flask app from flask import Flask app = Flask(__name__) @app.route('/') def helloworld(): re ...

  8. 编译Openwrt的log

    Openwrt配置: Target System (Ralink RT288x/RT3xxx) ---> Subtarget (MT7688 based boards) ---> Targ ...

  9. 【Codeforces 1114C】Trailing Loves (or L'oeufs?)

    [链接] 我是链接,点我呀:) [题意] 问你n!的b进制下末尾的0的个数 [题解] 证明:https://blog.csdn.net/qq_40679299/article/details/8116 ...

  10. Linux学习总结(3)——Linux实用工具

    1. Windows下同步Linux文件(Linux安装Samba和配置) 场景需求: 安装了Ubuntu在虚拟机上,但是代码编辑或者其它更多的操作的时候,还是习惯在windows下进行.如果wind ...