洛谷 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之内的节点.问最少要建多少个消防站,可以覆盖所有的节点 ...
随机推荐
- Firefly的角色跳转场景简单示例
源地址:http://bbs.9miao.com/thread-45790-1-2.html 本例演示的是模拟游戏服务端,让角色在场景1中跳转到场景2中.在实际游戏中,client将要跳转的角色id和 ...
- PHP 性能分析第三篇: 性能调优实战
注意:本文是我们的 PHP 性能分析系列的第三篇,点此阅读 PHP 性能分析第一篇: XHProf & XHGui 介绍 ,或 PHP 性能分析第二篇: 深入研究 XHGui. 在本系列的 ...
- EOJ-1708//POJ3334
题意: 有一个连通器,由两个漏斗组成(关于漏斗的描述见描述). 现向漏斗中注入一定量的水,问最终水的绝对位置(即y轴坐标) 思路: 总体来说分为3种情况. 1.两个漏斗可能同时装有水. 2.只可能a漏 ...
- hibernate annotation注解 主键ID自增长
@Id @SequenceGenerator(name="increment") @GeneratedValue(strategy=GenerationType.AUTO, gen ...
- 修改jmeter jvm参数
记录下常用的linux下 jmeter jvm参数修改,打开jmeter安装目录/bin/jmeter(非jmeter.sh) 1. 修改默认堆内存大小 #默认的 HEAP="-Xms512 ...
- Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤
原文地址: Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤 - 网络资源是无限的 - 博客频道 - CSDN.NET http://blog.csdn.net/fen ...
- 115. Distinct Subsequences
题目: Given a string S and a string T, count the number of distinct subsequences of T in S. A subseque ...
- 对Cost (%CPU) 粗略的理解
今天研究执行计划,看到执行计划里面有Cost (%CPU),我这边研究了一把,不知道对与否,拿出来晒晒 在Oracle 10g中,Oracle 把CPU的cost也统计在执行计划中去了, 这和以前的8 ...
- thinkphp框架 中 ajax 的应用
在thinkphp中,内置了ajax的方法,即: ajaxReturn("data","info","status"); data:传递的数 ...
- 修改VMware Workstation 界面语言
修改方法 我安装的VMware版本是10,找到VMware安装目录,我的是C:\Program Files\VMware\VMware Workstation\messages,里面有ja和zh-cn ...