题目链接

看起来似乎跟最小点覆盖有点像。但区别在于:

最小点覆盖要求所有边在其中,而本题要求所有点在其中。

即:一个点不选时,它的儿子不一定需要全选。

画图理解:



对于这样一幅图,本题中可以这样选择:3,53,53,5:

333将相邻的点2,42,42,4覆盖,而555将相邻的点1,61,61,6覆盖,因此所有点都被覆盖了。

那么就必须修改状态了。

Dynamic Programing

考虑对于一个点,如果它被覆盖了,只有三种可能:

  1. 自己被标记
  2. 父亲被标记
  3. 儿子被标记

因此我们设计状态:

  1. dp[now][0]dp[now][0]dp[now][0]为自己被标记
  2. dp[now][1]dp[now][1]dp[now][1]为父亲被标记
  3. 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]保安站岗的更多相关文章

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

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

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

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

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

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

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

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

  5. P2458 [SDOI2006]保安站岗[树形dp]

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

  6. 洛谷 P2458 [SDOI2006]保安站岗

    题目传送门 解题思路: 树形DP 可知一个点被控制有且仅有一下三种情况: 1.被父亲节点上的保安控制 2.被儿子节点上的保安控制 3.被当前节点上的保安控制 我们设dp[0/1/2][u]表示u节点所 ...

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

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

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

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

  9. [SDOI2006] 保安站岗

    题目链接 第一遍不知道为什么就爆零了…… 第二遍改了一下策略,思路没变,结果不知道为什么就 A 了??? 树形 DP 经典问题:选择最少点以覆盖树上所有点(边). 对于本题,设 dp[i][0/1][ ...

随机推荐

  1. DataTable和实体类之间的转换

    using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.R ...

  2. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 显示代码:变量赋值

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  3. Caffe2 图像预处理(Image Pre-Processing)[6]

    学习如何使得图像符合预训练模型的需求,或者用其他数据集的图像来测试自己的模型. - 调整大小 - 缩放 - HWC和CHW,数据通道交换 - RGB和BGR,颜色通道的交换 - Caffe2的图像预处 ...

  4. SwiftStack 因战略转变而裁员

    导读 销售团队在前段圣诞节来临前面临裁减的糟糕处境.企业云存储公司SwiftStack进行了裁员,人数不详,公司规模因此缩小. IT外媒The Register获悉,这家公司裁掉了大概一半的人员,但总 ...

  5. Android之收音机UI实现(转)

    源码: http://www.2cto.com/kf/201211/171417.html 最近在研究收音机的源码,本来想把收音机从源码中提取出来,做成一个单独的应用,但是,收音机需要底层的支持,所以 ...

  6. The way get information from mssql by using excel vba and special port

    Yes,  we can get information from mssql by using excel vba.  But the default port of MSSQL is  1433. ...

  7. 学习Flutter应用开发有用的代码/库/专有技术列表

    当我开始使用Flutter开发该应用程序时,我开始担心:“最好的书写方式是什么?”以及“放置它的效果如何?”在这种情况下,您将需要学习和参考GitHub发布的代码和应用程​​序. 因此,我收集了似乎对 ...

  8. Python - metaclass元类

    参考 https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014319106919 ...

  9. 复习jquery菜鸟教程

    https://www.runoob.com/jquery/jquery-plugin-treeview.html

  10. Ajax请求回调地狱及解决方案(promise、async和await)

    谈及回调地狱发生得情况和解决办法,就必须追溯到原生ajax请求. 先列出服务器提供的数据接口: // 服务器端接口 app.get('/data1', (req, res) => { res.s ...