[SMOJ1783]移动信号
来源:互联网 发布:数据库进销存管理系统 编辑:程序博客网 时间:2024/05/01 15:12
题目描述
给出一个树,有
N 个结点,结点编号从 1 至N 。假如在第i 个结点建立一个信号塔,那么与第i 个结点有边相连的结点就能接受到信号,当然第i 个结点本身也能接受到信号。问题是:至少要在多少个结点建立信号塔,才能使得所有的结点都能接收到信息。
输入格式 1783.in
第一行,一个整数
N 。1≤N≤10,000 接下来有
N−1 行,每行两个整数:a b ,表示结点a 和结点b 有边相连。1≤A≤N ;1≤B≤N ;A≠B
输出格式 1783.out
一个整数。
输入样例 1783.in
5
1 3
5 2
4 3
3 5
输出样例 1783.out
2
这个题……也是一道好题,挺能够考察细心程度的。
题目意思写得已经够简洁明了,这里就不再重复概括一下了,反正也不会短到哪里去。
此题我初做的时候,只用
这是因为,我忽略了一个非常关键的问题。
不妨先把样例画出来观察一下吧。
如果在 3 建一个信号塔的话,不仅会对它的儿子 1 和 4 造成影响,同时也会影响到它的父亲 5!
也就是说,我们做 DP 的时候还不能单纯只考虑儿子,还得想想父亲。那这样不是会有后效性的吗?
一开始我也是这样想的,但是,仔细思考一下。其实一个结点对父亲的影响只有一层而已,到了它爷爷那一辈,最多跟它父亲有联系,跟它自己可就没了。
于是我们可以这样记,首先前提条件是自己和子树一定要全部收到信号,然后有三种情况:要么是自己建一个信号塔,要么是自己不建,靠父亲给自己提供信号;要么是自己不建,靠儿子(们)给自己提供信号。
有了这样的状态就非常好办了,每种情况考虑清楚就可以转移了。
对于自己建信号塔的情况,儿子建不建都无所谓,也就是
如果自己不建,依赖父亲给自己提供信号,那么至少儿子不能依赖自己了,它们要么自力更生建一个,要么再依赖它们的儿子(也就是自己的孙子们),即
最后一种情况,自己不建,依赖儿子给自己提供信号,首先还是一样,儿子没办法依赖自己了。
显然,其实只要有一个儿子是自己建,那么它就能给自己提供信号;至于其他的儿子就可建可不建了,即
奇怪。看起来,依赖父亲和依赖儿子的转移方程怎么是一模一样的?这不大可能吧?
确实如此,我们忽略了一种情况。
万一,在依赖儿子的时候,所有儿子都是自己不建会更优一些,那么没有一个儿子建了信号塔。此时我们就无法依赖儿子了!
所以要单独讨论一下,对于这种特殊情况,要找一个儿子来建塔。找谁好呢?
现在我们已经算得了一个
假设找儿子
显然要让新的值最小,那么必须让
于是可以加个 bool 变量,看在考虑每一个儿子
可能会有疑问,万一
不会的。如果
边界条件为:对于所有的叶子节点,依赖儿子的情况为无穷大,因为它们没有儿子可以依赖。
所以,我们设计状态的时候一定要注意无后效性的问题。倘若用一种可能会有后效性的状态来描述,可能就会出现漏洞,从而导致满盘皆输。
参考代码:
#include <algorithm>#include <climits>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;const int maxn = 1e5 + 100;int n;//采用数组模拟指针储存树int head[maxn];struct Edge { int to; int next; Edge () { to = next = 0; }} edge[maxn];int cnt = 0;void addEdge(int u, int v) { edge[++cnt].to = v; edge[cnt].next = head[u]; head[u] = cnt;}int dp[maxn][5]; //0 依赖于儿子 1 自己建 2 依赖于父亲void dfs(int root, int pre) { dp[root][1] = 1; bool f = false; //看是否每个儿子都不建塔 int minD = INT_MAX; // for (int i = head[root]; i; i = edge[i].next) { int child = edge[i].to; if (child != pre) { dfs(child, root); dp[root][0] += min(dp[child][0], dp[child][1]); //若该儿子建塔更优,则根结点是可以依靠它的 f = f || dp[child][1] <= dp[child][0]; minD = min(minD, dp[child][1] - dp[child][0]); dp[root][1] += min(dp[child][0], min(dp[child][1], dp[child][2])); dp[root][2] += min(dp[child][0], dp[child][1]); } } if (!f) dp[root][0] += minD; //所有儿子都不建塔,强制建一个代价最小的 if (!dp[root][0]) dp[root][0] = INT_MAX; //叶子结点不能靠儿子}int main(void) { freopen("1783.in", "r", stdin); freopen("1783.out", "w", stdout); scanf("%d", &n); memset(head, 0, sizeof head); for (int i = 1; i < n; i++) { int a, b; scanf("%d%d", &a, &b); addEdge(a, b); addEdge(b, a); } memset(dp, 0, sizeof dp); dfs(1, 0); printf("%d\n", min(dp[1][0], dp[1][1])); return 0;}
- [SMOJ1783]移动信号
- FDN 移动手机卡信号
- FDN 移动手机卡信号
- 移动信号(树形Dp)
- 联通无需换号码可用移动信号
- Android 移动网络信号种类详解
- android5.1.1 获取当前移动信号强度
- 集训-移动信号(树形DP)
- 钻井平台移动信号放大系统设计方案
- 【移动】获取客户微信号信息
- [网络]插入移动卡和非移动卡,非移动卡为主卡时无信号
- [FAQ20103][Network]插入移动卡和非移动卡,非移动卡为主卡时无信号
- 解决一加手机没有移动3G信号
- 高通新技术:改善地铁和商场移动网络信号
- Unity3D移动端电量与wifi信号的获取
- 信号
- 信号
- 信号
- 数据权限实现(Mybatis拦截器+JSqlParser)
- raise IOError, 'Not a gzipped file'
- 常用计算机远程控制软件介绍
- JS 调取摄像头
- C++构造函数初始化列表与赋值
- [SMOJ1783]移动信号
- JMeter目录及关键配置分析
- 循环赛日程表
- Java 接口与抽象类
- 使用canvas绘制扇形图
- Web开发&文件上传下载及编码解码
- MyEclipse
- eclipse mvn jetty 远程调试
- Father-Child