原题链接:https://www.luogu.org/problemnew/show/P2279
消防局的设立
题目描述
2020 2020 2020年,人类在火星上建立了一个庞大的基地群,总共有 n n n个基地。起初为了节约材料,人类只修建了 n − 1 n-1 n−1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。如果基地 A A A到基地 B B B至少要经过 d d d条道路的话,我们称基地 A A A到基地 B B B的距离为 d d d。
由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过 2 2 2的基地的火灾。
你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。
输入输出格式
输入格式:
输入文件名为 i n p u t . t x t input.txt input.txt。
输入文件的第一行为 n ( n < = 1000 ) n (n<=1000) n(n<=1000),表示火星上基地的数目。接下来的 n − 1 n-1 n−1行每行有一个正整数,其中文件第i行的正整数为 a [ i ] a[i] a[i],表示从编号为 i i i的基地到编号为 a [ i ] a[i] a[i]的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有 a [ i ] < i a[i]<i a[i]<i。
输出格式:
输出文件名为 o u t p u t . t x t output.txt output.txt
输出文件仅有一个正整数,表示至少要设立多少个消防局才有能力及时扑灭任何基地发生的火灾。
输入输出样例
输入样例#1:
6
1
2
3
4
5
输出样例#1:
2
题解
贪心策略:每次都找到深度最深的没被覆盖的点,在它的爷爷设立消防站,这样决策没有后效性,也是当前能做出的最优决策。
所以我们把每个点按深度排序,记录每个点离最近的消防站的距离,当距离大于 2 2 2时在他爷爷设立消防站并更新爷爷的爸爸和爷爷的距离。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=1005;
int dad[M],dep[M],pt[M],dis[M],n,ans;
bool cmp(int a,int b){return dep[a]>dep[b];}
void in()
{
scanf("%d",&n);pt[1]=1,dis[0]=dis[1]=M;
for(int i=2;i<=n;++i)scanf("%d",&dad[i]),dep[i]=dep[dad[i]]+1,pt[i]=i,dis[i]=M;
}
void ac()
{
sort(pt+1,pt+1+n,cmp);
for(int i=1,v,f,ff;i<=n;++i)
{
v=pt[i],f=dad[v],ff=dad[f];
dis[v]=min(dis[v],min(dis[f]+1,dis[ff]+2));
if(dis[v]>2)dis[ff]=0,++ans,dis[dad[ff]]=min(dis[dad[ff]],1),dis[dad[dad[ff]]]=min(dis[dad[dad[ff]]],2);
}
printf("%d",ans);
}
int main(){in(),ac();}