树上边覆盖问题

例:luoguP2016 战略游戏

简述题意:

每个节点都能放一个士兵,每个士兵能看守与他相邻的所有边,求覆盖所有边最少需要多少士兵?

Solution:

设 \(f[x][1/0]\) 表示回溯到第 \(x\) 个点时所用士兵数量, \(1\) 表示在这里放一个士兵, \(0\) 表示不放

显然珂推得转移方程:

\[f[x][1] = 1 + \sum_{v \in son[x]}min(f[v][1],f[v][0])
\]
\[f[x][0] = \sum_{v \in son[x]} f[v][1]
\]

Code

#include<iostream>
#include<cstdio> using namespace std;
const int MAXN = 1610; struct edge{
int to, nxt;
}e[MAXN << 1];
int head[MAXN], num_edge;
int n, k;
int f[MAXN][2]; int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
return s * w;
} void add_edge(int from, int to){ e[++num_edge] = (edge){to, head[from]}, head[from] = num_edge; } void dfs(int x, int fa){
f[x][1] = 1;
// cout<<x<<endl;
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa) continue;
dfs(v, x);
f[x][1] += min(f[v][1], f[v][0]);
f[x][0] += f[v][1];
}
} int main()
{
n = read();
for(int i = 1, x; i <= n; ++i){
x = read(), x++;
k = read();
for(int j = 1, v; j <= k; ++j){
v = read(), v++;
add_edge(x, v), add_edge(v, x);
}
} dfs(1, 0); printf("%d", min(f[1][1], f[1][0])); return 0;
}

树上点覆盖问题

例:P2458 [SDOI2006]保安站岗

简述题意

每个保安可以保护自己的点和相邻点,求将树上所有点都覆盖最少所需保安数

Solution

设 \(f[u][0/1/2]\) 表示回溯到第 \(u\) 个点时所用士兵数量, \(0\) 表示在自己这里放一个士兵, \(1\) 表示被儿子覆盖, \(2\) 表示被父亲覆盖

转移方程:

\[f[u][0] = \sum_{v \in son[u]} min(f[v][0],f[v][1],f[v][2])
\]
\[f[u][1] = f[x][0] + \sum_{v \in son[u] \And \And v != x} min(f[v][0], min[v][1])
\]
\[f[u][2] = \sum_{v \in son[u]} min(f[v][0], f[v][1])
\]

感觉 \(f[u][0]\) 和 \(f[u][2]\) 的转移方程都比较显然

对于 \(f[u][1]\) 因为不同于树上边覆盖问题,它可以被自己的儿子覆盖,所以对儿子的要求是:要么是被自己覆盖,要么被自己的儿子覆盖

但对于 \(u\) 本身要保证自己的儿子中有一个是被自己覆盖,所以要求出最优的那个儿子 \(x\) 就好了,可以枚举所有儿子,这里介绍一种数学式子优化

最优的 \(x\) 满足 \(f[x][0] - min(f[x][0], f[x][1])\) 最小

参考题解

证明:

因为 \(x\) 满足 \(f[u][1] = f[x][0] + \sum_{v \in son[u] \And \And v != x} min(f[v][0], min[v][1])\)

设 \(F(u, x) = f[x][0] + \sum_{v \in son[u] \And \And v != x} min(f[v][0], min[v][1])\)

假设 \(x\) 不是最优的, 则必有一个 \(y\) 满足 \(F(u, x) > F(u, y)\)

将这个式子化简得(可以将相同的部分消掉)

\(f[x][0] - min(f[x][0], f[x][1]) > f[y][0] - min(f[y][0], f[y][1])\)

所以有最优的 \(x\) 满足 \(f[x][0] - min(f[x][0], f[x][1])\) 最小

证毕

下面是代码时间:

Code:

/*
Work by: Suzt_ilymics
Knowledge: ??
Time: O(??)
*/
#include<iostream>
#include<cstdio>
#include<cstring> using namespace std;
const int MAXN = 1e6+6;
const int inf = 0x3f3f3f3f;
struct edge{
int to, nxt;
}e[MAXN << 1];
int head[MAXN], num_edge; int read(){
int s = 0, w = 1;
char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') s = (s << 1) + (s << 3) + ch - '0', ch = getchar();
return s * w;
} int n;
int f[MAXN][3]; void add_edge(int from, int to){
e[++num_edge] = (edge){to, head[from]}, head[from] = num_edge;
} void dfs(int x, int fa){
int sson = 0;
int minn = 988888889;
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa) continue;
dfs(v, x);
f[x][0] += min(f[v][0], min(f[v][1], f[v][2]));
f[x][2] += min(f[v][0], f[v][1]);
if(f[sson][0] - min(f[sson][0], f[sson][1]) > f[v][0] - min(f[v][0], f[v][1])) sson = v;
}
f[x][1] = f[sson][0];
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa || v == sson) continue;
f[x][1] += min(f[v][0], f[v][1]);
}
} int main()
{
n = read();
for(int i = 1, m, u, v; i <= n; ++i){
u = read(), f[u][0] = read(), m = read();
for(int j = 1; j <= m; ++j){
v = read();
add_edge(u, v), add_edge(v, u);
}
}
f[0][0] = inf;
dfs(1, 0);
printf("%d", min(f[1][0], f[1][1]));
return 0;
}

其他两个树上点覆盖问题例题,稍微改一下输入即可,一个套路随便搞:

P2899 [USACO08JAN]Cell Phone Network G

T155737 搬书

最后欢迎大家来补充啊,团队私题要是涉及隐私的话可以联系我

DP中的树上边/点覆盖问题的更多相关文章

  1. 【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治

    题目描述  给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费 ...

  2. HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...

  3. GTK+中的树状列表构件(GtkTreeView)

    GTK+中的树状列表构件(GtkTreeView) GTK+中的树状列表构件(GtkTreeView) 在本章的GTK+程序设计教程中,我们将向大家重点介绍非常常用也有点复杂的构件--GtkTreeV ...

  4. dp乱写2:论dp在不在dp中(但在dp范畴)内的应用

    最近正儿八经的学习了dp,有一些题目非常明显看出来就是dp了比如说:过河卒.方格取数.导弹拦截.加分二叉树.炮兵阵地更加明显的还有:采药.装箱问题.过河.金明的预算方案.今天来谈谈dp的dp在不在dp ...

  5. MySQL中B+树索引的使用

    1)         不同应用中B+树索引的使用 对于OLTP应用,由于数据量获取可能是其中一小部分,建立B+树索引是有异议时的 对OLAP应用,情况比较复杂,因为索引的添加应该是宏观的而不是微观的. ...

  6. oracle中的树状查询

    oracle中的树状查询 工作中经常会遇到将数据库中的数据以树的形式展现的需求.以下我们来看一下该需求在Oracle中如何实现. 首先我们需要有一个树形的表结构(当然有时候会出现表结构不是典型的树形结 ...

  7. C#上移,下移TreeView中的树节点顺序

    C#上移,下移TreeView中的树节点顺序 2009-08-12 20:10 1494人阅读 评论(2) 收藏 举报 c#buttonobjectnullstring C#中,通过单击上移,下移按钮 ...

  8. JavaScript 数据结构与算法之美 - 非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?

    1. 前言 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手. 非线性表(树.堆),可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法 ...

  9. 【题解】ARC101F Robots and Exits(DP转格路+树状数组优化DP)

    [题解]ARC101F Robots and Exits(DP转格路+树状数组优化DP) 先删去所有只能进入一个洞的机器人,这对答案没有贡献 考虑一个机器人只能进入两个洞,且真正的限制条件是操作的前缀 ...

随机推荐

  1. 1.第一个QT程序

    第一个QT程序 应用程序类QApplication 窗口类MyWidget 进入事件循环 a.exec() 头文件 mywidget.h QApplication 文件Demo_pro 我怎么知道我用 ...

  2. JavaScript--总结一(变量+数据类型+运算符)

    JavaScript是什么? 是一门脚本语言(不需要编译,直接执行) 是一门解释性语言 是一门动态类型的语言 是一门基于对象的语言 JavaScript分为三个部分 1.ECMAScript  标准- ...

  3. Head First 设计模式 —— 08. 外观 (Facade) 模式

    思考题 想想看,你在 JavaAPI 中遇到过哪些外观,你还希望 Java 能够新增哪些外观? P262 println.log 日志接口.JDBC 接口 突然让想感觉想不出来,各种 API 都用得挺 ...

  4. Laya 踩坑日记 ---A* 导航寻路

    要做寻路,然后看了看laya 官方的例子,感觉看的一脸懵逼,早了半天的api 也没找到在哪有寻路的,最后一看代码,原来是用的github上的A星方案  https://github.com/bgrin ...

  5. 【Linux】kali 安装 python3 和 pip3(亲测有效)

    [Linux]kali 安装 python3 和 pip3 引言:   在使用kali的时候,经常会用到各种工具以及脚本,而大多数脚本都是以python编写的,但是烦就烦在python有2个版本,有些 ...

  6. Centos7 Nginx+PHP7 配置

    Centos7 Nginx+PHP7 配置 内容: 源码编译安装Nginx和PHP 配置PHP和Nginx,实现Nginx转发到PHP处理 测试 设置Nginx.PHP开机自启 安装的版本: Ngin ...

  7. Tomcat的整体架构

    Tomcat通过连接器和容器这两个核心组件完成整体工作,连接器负责处理socket连接和网络字节流与Request和Response对象的转化:容器负责加载和管理Servlet,以及具体处理Reque ...

  8. 使用Jenkins+Pipline 持构建自动化部署之安卓源码打包、测试、邮件通知

    一.引言 Jenkins 2.x的精髓是Pipeline as Code,那为什么要用Pipeline呢?jenkins1.0也能实现自动化构建,但Pipeline能够将以前project中的配置信息 ...

  9. 通用寄存器_MOV_ADD_SUB_AND_OR_NOT

    通用寄存器 MOV指令 注意:目标操作数与操作数宽度必须一样 MOV 目标操作数,源操作数 作用:拷贝源操作数到目标操作数 1.源操作数可以是立即数.通用寄存器.段寄存器.或者内存单元. 2.目标操作 ...

  10. 面试官:Netty的线程模型可不只是主从多Reactor这么简单

    笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...