洛谷 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之内的节点.问最少要建多少个消防站,可以覆盖所有的节点 ...
 
随机推荐
- Kafka server的的停止
			
这算是CountDownLatch的一个典型使用场景. kafka.Kafka对象的main方法中与此有关的代码为 // attach shutdown handler to catch contro ...
 - SaaS 公司如何应对 On-Call 挑战?
			
Cloud Insight 集监控.管理.计算.协作.可视化于一身,帮助所有 IT 公司,减少在系统监控上的人力和时间成本投入,让运维工作更加高效.简单.本文系国内 ITOM 行业领军企业 OneAP ...
 - python time相关操作
			
1.获取当前时间的两种方法: 代码如下: import datetime,timenow = time.strftime("%Y-%m-%d %H:%M:%S")print now ...
 - Making your local server accessible from anywhere
			
In reality you probably don’t want to host you websites on your local computer unless you have a ver ...
 - linux 修改命令行编码 乱码解决方案
			
修改/etc/default/locale命令:sudo vim /etc/default/locale1将下面这两行 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN:zh 修改为: ...
 - 到底该不该熟悉掌握struts2的ONGL呢?
			
其实,在学习网站开发过程中,其实不掌握ONGL也是可以的.我们完全可以使用JSTL和EL来代替OGNL. 只要存在要往页面传输内容,我们直接把对象放在request范围即可,这样我们就可以在jsp中使 ...
 - git 命令整理
			
记录一些git 命令,以便自己以后查阅 基本命令 1.git add (保存工作区的变动到暂存区) git add . 和git add -A把整个工作区添加到暂存区 2.git commit ( ...
 - 李洪强漫谈iOS开发[C语言-011] - C语言标示符
			
/** * 标示符 2016年 7月 14日 01 低级语言和高级语言的最大不同: 低级语言用的是机器指令 高级语言就是写一些人可以看得懂的代码-汇编语言 标示符 就是名字 命名规则: 1) 只 ...
 - Centos之LAMP环境搭建
			
原文:http://blog.sina.com.cn/s/blog_c02ed6590101d2sl.html 一.安装 MySQL 首先来进行 MySQL 的安装.打开超级终端,输入: [root@ ...
 - CentOS7.1 Xshell 经常掉线 Connection closed by foreign host
			
XShell如果经常对CentOS掉线,则VNC肯定连接不上 但是ping CentOS的IP又能ping通,主要原因还是因为sshd的设置问题 #进入ssh目录 cd /etc/ssh #修改ssh ...