\(\\\)

Description


给出一棵 \(n\) 个节点以 \(1\) 为根的树,一个节点的覆盖半径是 \(1\) ,点有点权 \(val_x\) 。

选择一些点,使得点权和最小,同时每个节点要么被选择要么被周围的点覆盖。

  • \(n\le 1500,0\le val_x\le 10^4\)

\(\\\)

Solution


树形DP 的讨论。

注意到覆盖有可能呈现出两层都没有选点的情况 (下面被子树覆盖,上面被父节点覆盖),所以状态设计要注意。

设\(f[i][0/1/2]\),表示节点 \(i\) 及其子树的覆盖代价,明确定义:

  • \(0\) 表示选择自己,覆盖整个子树的最小代价
  • \(1\) 表示第 \(i\) 个节点被自己的子树的根节点覆盖,不选择自己的最小代价
  • \(2\) 表示第 \(i\) 个节点被父节点覆盖,此时当前节点的所有子树都已经完成覆盖的最小代价

转移讨论起来就很方便了。

\(0\) :显然要选自己,所以所有子树选什么都合法,对每个子树累加 \(min(f[v][0],f[v][1],f[v][2])\) 。

\(2\):不选自己,子树内部显然不能再向当前点提出需求,所以对子树累加 \(min(f[v][0],f[v][1])\) 。

\(1\) 的转移有点意思。

如果我们贪心的选,选择 \(0\) 状态最小的子树,剩下的子树都选 \(1\) 状态,不一定是最优的。

因为这个 \(0\) 状态最小的子树,他的 \(1\) 状态可能会更小的多,这个差值完全能够允许另一个 \(1\) 状态变成 \(0\) 状态。

\(\\\)

所以考虑替换, \(yy\) 出来一个比较好的写法。

先对所有子树求出 \(sum=min(f[v][0],f[v][1])\) 。

同时维护 \(tmp=min(\ f[v][0]-\min(f[v][0],f[v][1])\ )\)。

\(\\\)

这个 \(sum\) 的含义是,不考虑子树覆盖当前节点, 子树内部覆盖的最小值,可以发现其实就是 \(f[u][2]\) 。

\(tmp\) 的含义就是,把这个 \(sum\) 集合里的任意一个点不管之前选的什么,现在变成 \(0\) 状态的最小代价。

如果之前求 \(sum\) 的时候选了一个 \(0\) 状态,那么这个 \(tmp\) 显然是 \(0\) 。

如果之前没有选到任意一个 \(0\) 状态,那么这个 \(tmp\) 就是所有的 \(1\) 状态里,变成 \(0\) 状态的最小代价。

所以有 \(f[v][1]=f[v][2]+tmp\) 。

\(\\\)

Code


#include<cmath>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1510
#define gc getchar
#define R register
#define inf 2000000000
using namespace std; inline int rd(){
int x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
} int n,m,tot,hd[N],f[N][3],val[N]; struct edge{int to,nxt;}e[N<<1]; inline void add(int u,int v){
e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
} //0: 选自己
//1: 选子树内覆盖自己
//2:选父节点覆盖自己 void dfs(int u,int fa){
int mn=inf;
f[u][0]=val[u]; f[u][2]=0;
for(R int i=hd[u],v;i;i=e[i].nxt)
if((v=e[i].to)!=fa){
dfs(v,u);
f[u][0]+=min(f[v][2],min(f[v][1],f[v][0]));
f[u][2]+=min(f[v][1],f[v][0]);
mn=min(mn,f[v][0]-min(f[v][1],f[v][0]));
}
f[u][1]=f[u][2]+mn;
} int main(){
n=rd();
memset(f,0x3f,sizeof(f));
for(R int i=1,u,cnt;i<=n;++i){
u=rd(); val[u]=rd(); cnt=rd();
for(R int j=1,v;j<=cnt;++j){v=rd();add(u,v);add(v,u);}
}
dfs(1,0);
printf("%d\n",min(f[1][0],f[1][1]));
return 0;
}

[ SDOI 2006 ] 保安站岗的更多相关文章

  1. 【Luogu2458】保安站岗(动态规划)

    [Luogu2458]保安站岗(动态规划) 题面 题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地 ...

  2. C++ 洛谷 P2458 [SDOI2006]保安站岗 from_树形DP

    P2458 [SDOI2006]保安站岗 没学树形DP的,看一下. 题目大意:一棵树有N个节点,现在需要将所有节点都看守住,如果我们选择了节点i,那么节点i本身,节点i的父亲和儿子都会被看守住. 每个 ...

  3. 【题解】保安站岗[P2458]皇宫看守[LOJ10157][SDOI2006]

    [题解]保安站岗[P2458]皇宫看守[LOJ10157][SDOI2006] 传送门:皇宫看守\([LOJ10157]\) 保安站岗 \([P2458]\) \([SDOI2006]\) [题目描述 ...

  4. Luogu P2458 [SDOI2006]保安站岗(树形dp)

    P2458 [SDOI2006]保安站岗 题意 题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下 ...

  5. 洛谷【P2458】[SDOI2006]保安站岗 题解 树上DP

    题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...

  6. [luogu 2458][SDOI2006]保安站岗

    题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...

  7. 洛谷P2458 保安站岗

    传送门啦 分析: 树形dp刚刚入门,这是我做的第一个一个点同时受父亲节点和儿子节点控制的题目. 由于这个题中某一个点放不放保安与父亲和儿子都有关系(因为线段的两个端点嘛),所以我们做题时就要考虑全面. ...

  8. Luogu P2458 [SDOI2006]保安站岗【树形Dp】

    题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...

  9. [Luogu2458][SDOI2006]保安站岗

    题目描述 五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序. 已知整个地下超市的所有通道呈一棵树的形状:某些通道之间可以互 ...

随机推荐

  1. Servlet的服务端响应

    以下内容引用自http://wiki.jikexueyuan.com/project/servlet/server-response.html: 当一个Web服务器对浏览器响应一个HTTP请求时,响应 ...

  2. Kettle循环删除数据

    1.问题描述: 某个系统原库的数据同步到备份库.但是由于原库的的数据会物理删除,此时需要删除备份库的数据. 2.不理想的解决1: 1)首先从备份库获取该表的所有ID: 2)循环备份库的ID,去原库检测 ...

  3. linux network name space

    linux network namespace概念类似于网络中的 VRF (virtual routing and forwarding).但是,你不知道VRF的概念也没关系,下面我们通过一个简单的介 ...

  4. CF # 369 D2 D、E

    D,只要抓住每个点只有一个出度,那么图就能分成几个部分,而且可以发现,一个部分最多一个环. #include <iostream> #include <cstdio> #inc ...

  5. Python学习系列之异常处理

    什么是异常处理 python内置了一套try···except···finally的错误处理机制 当程序出错的时候进行捕捉,然后根据捕捉到的错误信息进行响相应的处理 常用的内建异常 初识异常处理 如例 ...

  6. Fragment进阶(五)-----&gt;监听fragment回退事件

    activity_main.xml <? xml version="1.0" encoding="utf-8"?> <LinearLayout ...

  7. Android 网络学习之获取server文本文件

    上次我们学习怎样从网络上获取一张图片,今天我们学习怎样从网络上获取文本文件.以XML文件为样例. 由于XML文件在实际开发中最为常见. 我们以以下图片为样例学习怎样从网络上获取XML文件 我们的xml ...

  8. 关于mysql建立索引 复合索引 索引类型

    这两天有个非常强烈的感觉就是自己在一些特别的情况下还是hold不住,脑子easy放空或者说一下子不知道怎么去分析问题了,比方,问"hash和btree索引的差别",这非常难吗.仅仅 ...

  9. FreeRTOS系列第14篇---FreeRTOS任务通知

    注:本文介绍任务通知的基础知识,具体源代码分析见<FreeRTOS高级篇8---FreeRTOS任务通知分析> 每一个RTOS任务都有一个32位的通知值,任务创建时,这个值被初始化为0.R ...

  10. 网络学习笔记:TCP/IP连网和Internet

    1.网关 由硬件和软件组成,实现不同网段间的数据传送. 常用路由器充当网关. 网关通常维护一份路由表,但只有少量的编址信息.它用这些信息把数据转发到知道更多信息的网关. 组成互联网骨干的网关称为核心网 ...