树上边覆盖问题

例: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. active mq 简单配置

    ---恢复内容开始--- 在activemq.xml 配置activemq的响应配置: 配置消息持久化: <persistenceAdapter>             <!-- ...

  2. 手把手教你实现自定义Spring Boot的 Starter

    引言 上篇文章<天天用SpringBoot,它的自动装配原理却说不出来>我们有说springBoot的自动装配怎么实现的(建议最好先看下篇文章,因为前后有关系),这篇文章的话我们就自己来实 ...

  3. 超长JVM总结,面试必备

    什么是JVM JVM 是可运行 Java 代码的假想计算机 ,包括一套字节码指令集.一组寄存器.一个栈.一个垃圾回收,堆 和 一个存储方法域.JVM 是运行在操作系统之上的,它与硬件没有直接的交互. ...

  4. redis基础-Remote Dictionary Server

    Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念. Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置dat ...

  5. git基础-git别名

    Git 并不会在你输入部分命令时自动推断出你想要的命令. 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名. 这里有一些例子你可以试试: $ ...

  6. linux根文件系统 /etc/resolv.conf 文件详解

    Linux根文件系统/etc/resolv.conf文件,它是DNS客户机配置文件,用于设置DNS服务器的IP地址及DNS域名,还包含了主机的域名搜索顺序.该文件是由域名解析器(resolver,以恶 ...

  7. 一张图看懂sql的各种join

    下图展示了 LEFT JOIN.RIGHT JOIN.INNER JOIN.OUTER JOIN 相关的 7 种用法.

  8. VUE项目性能优化实践——通过懒加载提升页面响应速度

    本文由葡萄城技术团队原创并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 最近我司因业务需求,需要在一个内部数据分析平台集成在线Excel功能,既然我 ...

  9. Java并发包源码学习系列:AQS共享式与独占式获取与释放资源的区别

    目录 Java并发包源码学习系列:AQS共享模式获取与释放资源 独占式获取资源 void acquire(int arg) boolean acquireQueued(Node, int) 独占式释放 ...

  10. Java 实现简单的 Socket 通信

    Java socket 封装了传输层的实现细节,开发人员可以基于 socket 实现应用层.本文介绍了 Java socket 简单用法. 1. 传输层协议 传输层包含了两种协议,分别是 TCP (T ...