DP中的树上边/点覆盖问题
树上边覆盖问题
例:luoguP2016 战略游戏
简述题意:
每个节点都能放一个士兵,每个士兵能看守与他相邻的所有边,求覆盖所有边最少需要多少士兵?
Solution:
设 \(f[x][1/0]\) 表示回溯到第 \(x\) 个点时所用士兵数量, \(1\) 表示在这里放一个士兵, \(0\) 表示不放
显然珂推得转移方程:
\]
\]
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;
}
树上点覆盖问题
简述题意
每个保安可以保护自己的点和相邻点,求将树上所有点都覆盖最少所需保安数
Solution
设 \(f[u][0/1/2]\) 表示回溯到第 \(u\) 个点时所用士兵数量, \(0\) 表示在自己这里放一个士兵, \(1\) 表示被儿子覆盖, \(2\) 表示被父亲覆盖
转移方程:
\]
\]
\]
感觉 \(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
最后欢迎大家来补充啊,团队私题要是涉及隐私的话可以联系我
DP中的树上边/点覆盖问题的更多相关文章
- 【bzoj3672】[Noi2014]购票 斜率优化dp+CDQ分治+树的点分治
题目描述 给出一棵以1为根的带边权有根树,对于每个根节点以外的点$v$,如果它与其某个祖先$a$的距离$d$不超过$l_v$,则可以花费$p_vd+q_v$的代价从$v$到$a$.问从每个点到1花费 ...
- HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca
Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...
- GTK+中的树状列表构件(GtkTreeView)
GTK+中的树状列表构件(GtkTreeView) GTK+中的树状列表构件(GtkTreeView) 在本章的GTK+程序设计教程中,我们将向大家重点介绍非常常用也有点复杂的构件--GtkTreeV ...
- dp乱写2:论dp在不在dp中(但在dp范畴)内的应用
最近正儿八经的学习了dp,有一些题目非常明显看出来就是dp了比如说:过河卒.方格取数.导弹拦截.加分二叉树.炮兵阵地更加明显的还有:采药.装箱问题.过河.金明的预算方案.今天来谈谈dp的dp在不在dp ...
- MySQL中B+树索引的使用
1) 不同应用中B+树索引的使用 对于OLTP应用,由于数据量获取可能是其中一小部分,建立B+树索引是有异议时的 对OLAP应用,情况比较复杂,因为索引的添加应该是宏观的而不是微观的. ...
- oracle中的树状查询
oracle中的树状查询 工作中经常会遇到将数据库中的数据以树的形式展现的需求.以下我们来看一下该需求在Oracle中如何实现. 首先我们需要有一个树形的表结构(当然有时候会出现表结构不是典型的树形结 ...
- C#上移,下移TreeView中的树节点顺序
C#上移,下移TreeView中的树节点顺序 2009-08-12 20:10 1494人阅读 评论(2) 收藏 举报 c#buttonobjectnullstring C#中,通过单击上移,下移按钮 ...
- JavaScript 数据结构与算法之美 - 非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?
1. 前言 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手. 非线性表(树.堆),可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法 ...
- 【题解】ARC101F Robots and Exits(DP转格路+树状数组优化DP)
[题解]ARC101F Robots and Exits(DP转格路+树状数组优化DP) 先删去所有只能进入一个洞的机器人,这对答案没有贡献 考虑一个机器人只能进入两个洞,且真正的限制条件是操作的前缀 ...
随机推荐
- 1.第一个QT程序
第一个QT程序 应用程序类QApplication 窗口类MyWidget 进入事件循环 a.exec() 头文件 mywidget.h QApplication 文件Demo_pro 我怎么知道我用 ...
- JavaScript--总结一(变量+数据类型+运算符)
JavaScript是什么? 是一门脚本语言(不需要编译,直接执行) 是一门解释性语言 是一门动态类型的语言 是一门基于对象的语言 JavaScript分为三个部分 1.ECMAScript 标准- ...
- Head First 设计模式 —— 08. 外观 (Facade) 模式
思考题 想想看,你在 JavaAPI 中遇到过哪些外观,你还希望 Java 能够新增哪些外观? P262 println.log 日志接口.JDBC 接口 突然让想感觉想不出来,各种 API 都用得挺 ...
- Laya 踩坑日记 ---A* 导航寻路
要做寻路,然后看了看laya 官方的例子,感觉看的一脸懵逼,早了半天的api 也没找到在哪有寻路的,最后一看代码,原来是用的github上的A星方案 https://github.com/bgrin ...
- 【Linux】kali 安装 python3 和 pip3(亲测有效)
[Linux]kali 安装 python3 和 pip3 引言: 在使用kali的时候,经常会用到各种工具以及脚本,而大多数脚本都是以python编写的,但是烦就烦在python有2个版本,有些 ...
- Centos7 Nginx+PHP7 配置
Centos7 Nginx+PHP7 配置 内容: 源码编译安装Nginx和PHP 配置PHP和Nginx,实现Nginx转发到PHP处理 测试 设置Nginx.PHP开机自启 安装的版本: Ngin ...
- Tomcat的整体架构
Tomcat通过连接器和容器这两个核心组件完成整体工作,连接器负责处理socket连接和网络字节流与Request和Response对象的转化:容器负责加载和管理Servlet,以及具体处理Reque ...
- 使用Jenkins+Pipline 持构建自动化部署之安卓源码打包、测试、邮件通知
一.引言 Jenkins 2.x的精髓是Pipeline as Code,那为什么要用Pipeline呢?jenkins1.0也能实现自动化构建,但Pipeline能够将以前project中的配置信息 ...
- 通用寄存器_MOV_ADD_SUB_AND_OR_NOT
通用寄存器 MOV指令 注意:目标操作数与操作数宽度必须一样 MOV 目标操作数,源操作数 作用:拷贝源操作数到目标操作数 1.源操作数可以是立即数.通用寄存器.段寄存器.或者内存单元. 2.目标操作 ...
- 面试官:Netty的线程模型可不只是主从多Reactor这么简单
笔者看来Netty的内核主要包括如下图三个部分: 其各个核心模块主要的职责如下: 内存管理 主要提高高效的内存管理,包含内存分配,内存回收. 网通通道 复制网络通信,例如实现对NIO.OIO等底层JA ...