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湖南 消防局的设立的更多相关文章

  1. 【洛谷P2279】[HNOI2003]消防局的设立

    消防局的设立 题目链接 贪心:每次取出深度最大的节点,若没有被覆盖到,要想覆盖它, 最优的做法显然是将它的爷爷设为消防局 (因为该节点深度为最大,选兄弟.父亲所覆盖的节点,选了爷爷后都能够覆盖) 用优 ...

  2. 题解【洛谷P2279】[HNOI2003]消防局的设立

    题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有\(n\)个基地.起初为了节约材料,人类只修建了\(n-1\)条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成 ...

  3. 【洛谷2279】[HNOI2003] 消防局的设立(贪心)

    点此看题面 大致题意: 给你\(N\)个点(其中\(1\)号点为根),并告诉你编号为\(2\sim N\)的点的父亲(\(fa[i]<i\)),现在要在树上选择尽量少的关键点(消防局),使得任意 ...

  4. 洛谷 P2279 [HNOI2003]消防局的设立 (树形dp or 贪心)

    一看到这道题就知道是树形dp 之前做过类似的题,只不过保护的范围是1 所以简单很多. 这道题保护的范围是2,就复杂了很多. 我就开始列状态,然后发现竟然有5种 然后我就开始列方程. 但是我考虑的时候是 ...

  5. 洛谷P2279 [HNOI2003]消防局的设立

    题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...

  6. 洛谷 P2279 [HNOI2003]消防局的设立

    题目描述 2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地.起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状 ...

  7. 洛谷 P2279 [HNOI2003]消防局的设立 题解

    每日一题 day34 打卡 Analysis 这道题的正解本来是树形dp,但要设5个状态,太麻烦了.于是我就用贪心试图做出此题,没想到还真做出来了. 考虑当前深度最大的叶子结点,你肯定要有一个消防局去 ...

  8. 洛谷P2279 消防局的设立 [HNOI2003] 贪心

    正解:贪心 解题报告: 传送门! 这题贪心得挺显然的,,,?居然能有蓝,,,是蓝题太水了嘛,,,? 简单说下,这题一看到就能想到,对最低的没被覆盖到的点给它的祖父建一个消防局 没了? 哦这题实现还挺有 ...

  9. 洛谷P2279 消防局的设立【树形dp】

    题目:https://www.luogu.org/problemnew/show/P2279 题意:一棵树.在节点处建消防站,可以覆盖与他距离在2之内的节点.问最少要建多少个消防站,可以覆盖所有的节点 ...

随机推荐

  1. hdu 1024

    参考了一下 http://moxi466839201.blog.163.com/blog/static/18003841620110220374942/ 滚动数组   状态转移方程不太好理解 .... ...

  2. spoj 62

    看了题解  自己好水   ...... #include <cstdio> #include <cstdlib> struct node { int x,y; }; node ...

  3. 写给 iOS 开发者的 Hopper + lldb 简介

    最近,关于 @Steipete 在Radar发布的帖子,笔者看到很多人在问「你是怎么理解那个伪代码的」.笔者想写博客已经有一段时间了,现在正好就此发表第一篇博文.笔者在一个叫 Hopper 的工具上花 ...

  4. 第一章、关于SQL Server数据库的备份和还原(sp_addumpdevice、backup、Restore)

    在sql server数据库中,备份和还原都只能在服务器上进行,备份的数据文件在服务器上,还原的数据文件也只能在服务器上,当在非服务器的机器上启动sql server客户端的时候,也可以通过该客户端来 ...

  5. POJ 3904 Sky Code

    题意:给定n个数ai, ai <= 10000, n <= 10000, 从中选出4个数要求gcd为1,这样的集合有多少个? 分析:首先总共集合nCr(n, 4) = n*(n-1)*(n ...

  6. photoshop:制作木板木纹

    1.设置颜色为木头相近颜色 2.滤镜->渲染->云彩 3.滤镜->杂色->添加杂色 4.滤镜->模糊->动感模糊 5.用矩形选取选取某块区域 6.滤镜->扭曲 ...

  7. Oracle学习笔记之数据类型

    1. mysql和oracle做数据同步.其中表的一个字段在mysql中设置为varchar(6),Oracle中为varchar2(6)   但mysql中能正常存放的数据同步到oracle中却抱O ...

  8. Windbg调试命令详解(3)

    3 进程与线程 既可以显示进程和线程列表,又可以显示指定进程或线程的详细信息.调试命令可以提供比taskmgr更详尽的进程资料,在调试过程中不可或缺. 3.1 进程命令 进程命令包括这些内容:显示进程 ...

  9. Oracle Length 和 Lengthb 函数说明 .(用来判断记录值里是否有中文内容)

    一.官网的说明 http://download.oracle.com/docs/cd/E11882_01/server.112/e26088/functions088.htm#SQLRF00658 P ...

  10. UVa 11040 (水题) Add bricks in the wall

    题意: 45块石头如图排列,每块石头上的数等于下面支撑它的两数之和,求其余未表示的数. 分析: 首先来计算最下面一行的数,A71 = A81 + A82 = A91 + 2A92 + A93,变形得到 ...