洛谷 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之内的节点.问最少要建多少个消防站,可以覆盖所有的节点 ...
随机推荐
- php站点
thinkphp wordpress 记事狗 phpcms http://jingyan.baidu.com/article/4b07be3c61e93e48b380f3fd.html
- Flume学习——Flume中事务的定义
首先要搞清楚的问题是:Flume中的事务用来干嘛? Flume中的事务用来保证消息的可靠传递. 当使用继承自BasicChannelSemantics的Channel时,Flume强制在操作Chann ...
- Hybrid App 和 React Native 开发那点事
简介:Hybrid App(混合模式移动应用)开发是指介于Web-app.Native-App这两者之间的一种开发模式,兼具「Native App 良好用户交互体验的优势」和「Web App 跨平台开 ...
- ubuntu12 开机自动转到命令行
命令: sudo gedit /etc/default/grub 找到这一行 GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"改成 GRUB_CM ...
- 阿里云 EDAS-HSF 用户指南
阿里云 EDAS-HSF 用户指南 针对 EDAS v2.3.0©Alibaba EDAS 项目组2015/8/19 1 前言本文档旨在描述阿里云 EDAS 产品中应用服务化模块的基本概念,以及如何使 ...
- thinkphp 独立分组配置
详见tp官网. 此处为笔记: <?php return array( // 0,为普通分组,1为独立分组 ', // 独立分组目录 'APP_GROUP_PATH' => 'Modules ...
- Qt:使用自定义的字体
Qt:使用自定义的字体 1. 下载字体文件 2. 加载字体文件 3. 使用字体 QFontDatabase::addApplicationFont("XENOTRON.TTF" ...
- 微信支付开发1 微信支付URL配置
本文介绍微信支付申请时如何设置授权目录及URL. 一.选择支付类型 目前有两种支付类型 JS API网页支付 Native原生支付 如果没有特殊要求,两种都勾选. 二.支付授权目录 目前可以选择htt ...
- 登陆shell与交互式非登陆shell的区别
登录shell 所谓登录shell,指的是当用户登录系统时所取的那个shell,登录shell属于交互式shell. 登录shell将查找4个不同的启动文件来处理其中的命令. bash shell处理 ...
- GPS(1)核心API及3种列出LocationProvider的方法
GPS的常用API Android SDK为GPS提供了很多API,其中LocationManager类是这些API的核心.所有与GPS相关的操作都由LocationManager对象及其派生的对象完 ...