洛谷 P2279 03湖南 消防局的设立
2016-05-30 16:18:17
题目链接: 洛谷 P2279 03湖南 消防局的设立
题目大意:
给定一棵树,选定一个节点的集合,使得所有点都与集合中的点的距离在2以内
解法1:
贪心
首先DFS转化为有根树,每次取最深节点的爷爷进入集合
- //消防局的设立 03湖南
- //贪心
- #include<stdio.h>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- struct node
- {
- int deep;
- int id;
- };
- node f[maxn];
- int marked[maxn];
- int father[maxn];
- struct edge
- {
- int to;
- int next;
- edge(){}
- edge(int to,int next):to(to),next(next){}
- };
- edge n[maxn*];
- int head[maxn];
- int cnt;
- int N;
- int ans;
- void insert(int x,int y)
- {
- n[++cnt]=edge(y,head[x]);
- head[x]=cnt;
- n[++cnt]=edge(x,head[y]);
- head[y]=cnt;
- return ;
- }
- void DFS(int x,int depth)
- {
- f[x].deep=depth;
- for(int i=head[x];i;i=n[i].next)
- {
- if(n[i].to!=father[x])
- {
- father[n[i].to]=x;
- DFS(n[i].to,depth+);
- }
- }
- return ;
- }
- bool comp(node a,node b)
- {
- return a.deep>b.deep;
- }
- void clear(int x,int len)
- {
- marked[x]=;
- if(len==)return ;
- for(int i=head[x];i;i=n[i].next)
- {
- clear(n[i].to,len+);
- }
- return ;
- }
- int main()
- {
- scanf("%d",&N);
- for(int i=;i<=N;i++)
- {
- int x;
- scanf("%d",&x);
- insert(i,x);
- }
- for(int i=;i<=N;i++)
- {
- f[i].id=i;
- }
- father[]=;
- DFS(,);
- sort(f+,f+N+,comp);
- for(int i=;i<=N;i++)
- {
- if(marked[f[i].id]==)
- {
- clear(father[father[f[i].id]],);
- ans++;
- }
- }
- printf("%d",ans);
- }
解法2:
恶心的树状动归
方程很多,看了好多题解才有了一点点想法
DP[x][len]就表示以x为根的子树中距离根为len的点全部建立消防局的最小消耗数
同时我们规定在某一个点建立消防局的条件是这个点所染的点的子树(包括他自己)不存在不合法的点
为了方便:我们将DP[x][len]改写为min(DP[x][0.1.2.....len]),son表示x节点的儿子
现在来分析DP[x][0]
在根节点染色,最多影响到根节点的孙子.而要使孙子以下的节点都被染色,应该将3代,4代或者5代染色(即min(DP[son][2],DP[son][3],DP[son][4]))
又因为我们之前为了方便将DP[x][len]改写为了最小值,所以直接累加即可
(其中DP[son][0]和DP[son][1]并不会影响结果,因为浅的节点本身要染的点一定大于等于深的节点)
再来分析DP[x][3],DP[x][4](个人觉得这两个数组更像是用来辅助更新的,好像不应该放在DP数组里)
这个比较好理解,根的3代就是根的儿子的2代,DP[x][3]=sigma(DP[son][2]);
同样也容易得到,根的4代就是根的儿子的3代,DP[x][4]=sigma(DP[son][3]);
最后来看DP[x][2],DP[x][1];
DP[x][2],不难发现,我们选择一个孙子,根节点就会合法,但是根节点的其他侧枝就不一定了
所以我们优先将所有侧枝以最佳方案染掉,sigma(DP[son][2]),再选择孙子(+DP[son][1]),并去掉重复统计的数据(-DP[son][2]);
DP[x][1],不难发现,我们选择一个儿子,根节点和这个节点的兄弟就都合法了,但是根节点其他孙子们就不一定了
所以我们优先将所有的孙子们以最佳方案染掉,sigma(DP[son][3]),再选择儿子(+DP[son][0]),并去掉重复统计的数据(-DP[son][3]);
综上:方程为
DP[x][0]=sigma(DP[son][4])+1(本身建立的方案);
DP[x][1]=sigma(DP[son][3])-min(DP[son][3]-DP[son][0]);
DP[x][2]=sigma(DP[son][2])-min(DP[son][2]-DP[son][1]);
DP[x][3]=sigma(DP[son][2]);
DP[x][4]=sigma(DP[son][3]);
- //消防局的设立 (03湖南)
- //树状动归
- #include<stdio.h>
- #include<algorithm>
- using namespace std;
- const int maxn=;
- struct edge
- {
- int to;
- int next;
- edge(){}
- edge(int to,int next):to(to),next(next){}
- };
- edge n[maxn*];
- int N;
- int DP[maxn][];
- int cnt;
- int head[maxn];
- int father[maxn];
- void insert(int x,int y)
- {
- n[++cnt]=edge(x,head[y]);
- head[y]=cnt;
- n[++cnt]=edge(y,head[x]);
- head[x]=cnt;
- return ;
- }
- void DFS(int x)
- {
- DP[x][]=1e8;
- DP[x][]=1e8;
- for(int i=head[x];i;i=n[i].next)
- {
- if(n[i].to==father[x])continue;
- father[n[i].to]=x;
- DFS(n[i].to);
- DP[x][]+=DP[n[i].to][];
- DP[x][]+=DP[n[i].to][];
- DP[x][]+=DP[n[i].to][];
- }
- DP[x][]++;
- for(int i=head[x];i;i=n[i].next)
- {
- if(n[i].to==father[x])continue;
- DP[x][]=min(DP[x][],DP[x][]-DP[n[i].to][]+DP[n[i].to][]);
- DP[x][]=min(DP[x][],DP[x][]-DP[n[i].to][]+DP[n[i].to][]);
- }
- for(int i=;i<=;i++)
- {
- DP[x][i]=min(DP[x][i],DP[x][i-]);
- }
- return ;
- }
- int main()
- {
- scanf("%d",&N);
- for(int i=;i<=N;i++)
- {
- int x;
- scanf("%d",&x);
- insert(i,x);
- }
- DFS();
- printf("%d",DP[][]);
- }
洛谷 P2279 03湖南 消防局的设立的更多相关文章
- 【洛谷P2279】[HNOI2003]消防局的设立
消防局的设立 题目链接 贪心:每次取出深度最大的节点,若没有被覆盖到,要想覆盖它, 最优的做法显然是将它的爷爷设为消防局 (因为该节点深度为最大,选兄弟.父亲所覆盖的节点,选了爷爷后都能够覆盖) 用优 ...
- 题解【洛谷P2279】[HNOI2003]消防局的设立
题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有\(n\)个基地.起初为了节约材料,人类只修建了\(n-1\)条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成 ...
- 【洛谷2279】[HNOI2003] 消防局的设立(贪心)
点此看题面 大致题意: 给你\(N\)个点(其中\(1\)号点为根),并告诉你编号为\(2\sim N\)的点的父亲(\(fa[i]<i\)),现在要在树上选择尽量少的关键点(消防局),使得任意 ...
- 洛谷 P2279 [HNOI2003]消防局的设立 (树形dp or 贪心)
一看到这道题就知道是树形dp 之前做过类似的题,只不过保护的范围是1 所以简单很多. 这道题保护的范围是2,就复杂了很多. 我就开始列状态,然后发现竟然有5种 然后我就开始列方程. 但是我考虑的时候是 ...
- 洛谷P2279 [HNOI2003]消防局的设立
题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...
- 洛谷 P2279 [HNOI2003]消防局的设立
题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...
- 洛谷 P2279 [HNOI2003]消防局的设立 题解
每日一题 day34 打卡 Analysis 这道题的正解本来是树形dp,但要设5个状态,太麻烦了.于是我就用贪心试图做出此题,没想到还真做出来了. 考虑当前深度最大的叶子结点,你肯定要有一个消防局去 ...
- 洛谷P2279 消防局的设立 [HNOI2003] 贪心
正解:贪心 解题报告: 传送门! 这题贪心得挺显然的,,,?居然能有蓝,,,是蓝题太水了嘛,,,? 简单说下,这题一看到就能想到,对最低的没被覆盖到的点给它的祖父建一个消防局 没了? 哦这题实现还挺有 ...
- 洛谷P2279 消防局的设立【树形dp】
题目:https://www.luogu.org/problemnew/show/P2279 题意:一棵树.在节点处建消防站,可以覆盖与他距离在2之内的节点.问最少要建多少个消防站,可以覆盖所有的节点 ...
随机推荐
- uva 10892
试了一下纯暴力 结果过了 无话可说 应该有更好的方法...... /**************************************************************** ...
- [Oracle]any, all解析
因为很少用到, 所以几乎忘记了这几个函数, 不过它们还是很有用的使用它们可以大大简化一些SQL文的语法, 至于效率问题, 如CCW所说它们和EXISTS, IN 之类没有什么差别, 而且要具体问题具体 ...
- Cloud Insight 和 BearyChat 第一次合体,好紧张!
说到 ChatOps 我们可能立刻想到是 Slack(啥?没听过?哦!),但是由于国内网络和语言的问题你可能无法拥有很好的体验了.那就把目光转回国内吧,国内的话就不得不提到 BearyChat 等 C ...
- 1962-Fibonacci
描述 This is an easy problem.I think Fibonacci sequence is familiar to you.Now there is another one. H ...
- linux下mysql修改数据库账户root密码
#先停止mysql,再运行下一句 $ mysqld_safe --user=mysql --skip-grant-tables --skip-networking & $ mysql -u r ...
- [Unity菜鸟] Unity发布web后,从HTML调用本地文件
1. 遇到的问题 从xml读数据,xml的编码用中文就会乱码,改编码格式就调用不了.目前采用默认的ANSI编码. .exe .txt .xlsx .xml .test Run √ ...
- Struts 2 + Spring2.5 + Hibernate3整合例子
一.效果 1. 2. 二.结构 1. 2.用到jar包 antlr-2.7.6.jaraspectjrt.jaraspectjweaver.jarc3p0-0.9.1.jarcglib-nodep-2 ...
- FocusWriter
2. FocusWriter 如果你正在从事某种写作——小说.博客.文档等——你绝对希望认识一下FocusWriter.它已经有近十年的发布历史了,但是一直是我们最喜欢的无分心写作应用之一.如果你希望 ...
- Java API ——Character类
1.Character类的概述 · Character 类在对象中包装一个基本类型 char 的值 · 此外,该类提供了几种方法,以确定字符的类别(小写字母,数字,等等),并将字符从大写转换成小写,反 ...
- Java API ——String类
1.String类概述 · 字符串是由多个字符组成的一串数据(字符序列),也可以看成是一个字符数组. · 字符串字符值“abc”也可以看成是一个字符串对象. · 字符串是常量,一旦被赋值,就不能被改变 ...