[Luogu][P2458] [SDOI2006]保安站岗
题目链接
看起来似乎跟最小点覆盖有点像。但区别在于:
最小点覆盖要求所有边在其中,而本题要求所有点在其中。
即:一个点不选时,它的儿子不一定需要全选。
画图理解:

对于这样一幅图,本题中可以这样选择:3,53,53,5:
333将相邻的点2,42,42,4覆盖,而555将相邻的点1,61,61,6覆盖,因此所有点都被覆盖了。
那么就必须修改状态了。
Dynamic Programing
考虑对于一个点,如果它被覆盖了,只有三种可能:
- 自己被标记
- 父亲被标记
- 儿子被标记
因此我们设计状态:
- dp[now][0]dp[now][0]dp[now][0]为自己被标记
- dp[now][1]dp[now][1]dp[now][1]为父亲被标记
- dp[now][2]dp[now][2]dp[now][2]为儿子被标记
那么如何转移呢?
自己被标记时,儿子的3种状态都是合法的,因此有:
dp[now][0]=∑min(dp[son][0],dp[son][1],dp[son][2])dp[now][0] = \sum \min(dp[son][0],dp[son][1],dp[son][2])dp[now][0]=∑min(dp[son][0],dp[son][1],dp[son][2])
而父亲被标记时,儿子不能被父亲标记了,只能自己标记或者被儿子的儿子标记。
dp[now][1]=∑min(dp[son][0],dp[son][2])dp[now][1] = \sum \min(dp[son][0],dp[son][2])dp[now][1]=∑min(dp[son][0],dp[son][2])
被儿子标记的情况就复杂一些。首先,被儿子标记时,所有儿子肯定无法被父亲标记,因此首先有:
dp[now][2]=∑min(dp[son][0],dp[son][2])dp[now][2] = \sum \min(dp[son][0],dp[son][2])dp[now][2]=∑min(dp[son][0],dp[son][2])
但是至少需要有一个儿子标记自己,才能让当前节点被儿子控制。如果一遍下来都没有选取dp[son][0]dp[son][0]dp[son][0]的情况怎么办呢?
我们考虑一个儿子,如果它被儿子标记更优,我们却强制它标记自己,那么代价就是dp[son][0]−dp[son][2]dp[son][0] - dp[son][2]dp[son][0]−dp[son][2]。
那么我们在遍历儿子时记录,看是否有儿子选取了控制自己,如果没有的话,就选择代价最小的那个儿子强制标记它即可。
Code
实现似乎没有太多坑点。
但要注意:当一个点是叶子结点时,dp[now][2]dp[now][2]dp[now][2]即被儿子标记的代价一定是+∞+\infty+∞,在代码中我直接并在了最后的处理中。可以感受一下。
另外就是这题的数据问题,虽然说题面是严格父亲对应儿子,但我建单向边死活过不了第三个点,改成双向边后AC。
最后答案,根节点不能被父亲控制。
#include <cstdio>
#include <cstring>
using namespace std;
template<typename T>
void read(T &r)
{
static char c; r=0;
for(c=getchar();c>'9'||c<'0';c=getchar());
for(;c>='0'&&c<='9';r=(r<<1)+(r<<3)+(c^48),c=getchar());
}
struct node
{
int to, next;
node() {}
node(const int &_to, const int &_next) : to(_to), next(_next) {}
} lines[3002];
int head[1501];
void add(const int &x, const int &y)
{
static int tot = 0;
lines[++tot] = node(y, head[x]), head[x] = tot;
}
template<typename T> inline T min(const T &a,const T &b){return a<b?a:b;}
template<typename T> inline T min(const T &a,const T &b,const T &c){return min(min(a,b),c);}
template<typename T> inline T max(const T &a,const T &b){return a>b?a:b;}
int n;
int w[1501];
int dp[1501][3];
//dp[i][0] 自己控制
//dp[i][1] 父亲控制
//dp[i][2] 儿子控制
void dfs(int now,int fa)
{
int v,minp = 999999999;
bool flag = true;//标记是否强制有一个儿子控制自己
dp[now][0] = w[now];
for(int p = head[now];p;p=lines[p].next)
{
v = lines[p].to;
if(v == fa)
continue;
dfs(v,now);
dp[now][0] += min(dp[v][2],dp[v][1],dp[v][0]);
dp[now][1] += min(dp[v][0],dp[v][2]);
if(dp[v][0] <= dp[v][2])
{
//此时可以直接选择这个儿子控制自己了
flag = false;
dp[now][2] += dp[v][0];
}
else
{
dp[now][2] += dp[v][2];
minp = min(minp,dp[v][0] - dp[v][2]);
}
}
if(flag)
dp[now][2] += minp;
}
int main()
{
read(n);
int m,u,x;
for(int i = 1;i<=n;++i)
{
read(u);
read(w[u]);
read(m);
while(m--)
{
read(x);
add(u,x);
add(x,u);//居然要双向边?!
}
}
dfs(1,0);
printf("%d",min(dp[1][0],dp[1][2]));
return 0;
}
[Luogu][P2458] [SDOI2006]保安站岗的更多相关文章
- Luogu P2458 [SDOI2006]保安站岗(树形dp)
P2458 [SDOI2006]保安站岗 题意 题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下 ...
- Luogu P2458 [SDOI2006]保安站岗【树形Dp】
题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...
- C++ 洛谷 P2458 [SDOI2006]保安站岗 from_树形DP
P2458 [SDOI2006]保安站岗 没学树形DP的,看一下. 题目大意:一棵树有N个节点,现在需要将所有节点都看守住,如果我们选择了节点i,那么节点i本身,节点i的父亲和儿子都会被看守住. 每个 ...
- [luogu 2458][SDOI2006]保安站岗
题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...
- P2458 [SDOI2006]保安站岗[树形dp]
题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...
- 洛谷 P2458 [SDOI2006]保安站岗
题目传送门 解题思路: 树形DP 可知一个点被控制有且仅有一下三种情况: 1.被父亲节点上的保安控制 2.被儿子节点上的保安控制 3.被当前节点上的保安控制 我们设dp[0/1/2][u]表示u节点所 ...
- 洛谷【P2458】[SDOI2006]保安站岗 题解 树上DP
题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...
- [Luogu2458][SDOI2006]保安站岗
题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...
- [SDOI2006] 保安站岗
题目链接 第一遍不知道为什么就爆零了…… 第二遍改了一下策略,思路没变,结果不知道为什么就 A 了??? 树形 DP 经典问题:选择最少点以覆盖树上所有点(边). 对于本题,设 dp[i][0/1][ ...
随机推荐
- C/C++网络编程7——多进程服务器端之fork函数
通过前面几节的内容,我们已经可以实现基本的C/S结构的程序了,但是当多个客户端同时向服务器端请求服务时,服务器端只能按顺序一个一个的服务,这种情况下,客户端的用户是无法忍受的.所以虚实现并发的服务器端 ...
- springBoot整合mybatis-plus关闭自动转换小驼峰命名规则
增加配置信息 mybatis-plus: configuration: map-underscore-to-camel-case: false
- urllib 库的代替品 requests 的用法
Requuests 官方的介绍时多么的霸气,之所以那么霸气,是因为 Requestts 相比于 urllib 在使用方面上会让开发者感到更加的人性化.更加简洁.更加舒适,并且国外的一些公司也在使用re ...
- JS原型链的理解和使用(二)
根据在创建对象的时候,创建出来的对象的__proto__指向创建这个对象的函数的prototype属性. 由于在调用对象的属性或者方法的时候会首先在对象的作用域中查找指定的属性或者方法,如果未找到则会 ...
- 3_05_MSSQL课程_Ado.Net_DataSet数据集
//创建一个内存的数据集 DataSet ds=new DataSet("LJK"); //创建一张内存表 DataTable dt01=new DataTable("d ...
- HTML5模板引擎 Thymeleaf 教程(转)
原文:http://www.open-open.com/lib/view/open1383622135586.html Thymeleaf是一个XML/XHTML/HTML5模板引擎,可用于Web与非 ...
- H.264 中的Annex B格式和AVCC格式
首先要理解的是没有标准的H.264基本流格式.文档中的确包含了一个Annex,特别是描述了一种可能的格式Annex B格式,但是这个并不是一个必须要求的格式.标准文档中指定了视频怎样编码成独立的包,但 ...
- 设计模式课程 设计模式精讲 15-2 桥接模式Coding
1 代码演练 1.1 代码演练1 1.2 代码演练2 1 代码演练 1.1 代码演练1 需求: 打印出从银行获取的账号类 优点: a 假如我只用用一个银行接口 去获取账号的内容,银行实现类要有定期 ...
- 嵊州普及Day6T3
题意:n个点,对于q个询问,有t秒及一个矩形的范围.在此矩形内的数每秒加1,若等于c,则下一秒变为0. 思路:t可能很大,%c+1就可以了.然后一个一个加起来就可以了. 见代码: #include&l ...
- python面向对象之练习题1
定义管理员类,管理员有属性(name,password),可以创建学校.创建课程.创建老师 定义老师类,老师有属性(name,password),可以添加课程.给学生打分,但发现学生没有购买课程时,不 ...