首页 > 技术文章 > P2279 [HNOI2003]消防局的设立

qkmqkm 2018-07-29 15:14 原文

题目描述

2020年,人类在火星上建立了一个庞大的基地群,总共有n个基地。起初为了节约材料,人类只修建了n-1条道路来连接这些基地,并且每两个基地都能够通过道路到达,所以所有的基地形成了一个巨大的树状结构。如果基地A到基地B至少要经过d条道路的话,我们称基地A到基地B的距离为d。

由于火星上非常干燥,经常引发火灾,人类决定在火星上修建若干个消防局。消防局只能修建在基地里,每个消防局有能力扑灭与它距离不超过2的基地的火灾。

你的任务是计算至少要修建多少个消防局才能够确保火星上所有的基地在发生火灾时,消防队有能力及时扑灭火灾。

输入输出格式

输入格式:

 

输入文件名为input.txt。

输入文件的第一行为n (n<=1000),表示火星上基地的数目。接下来的n-1行每行有一个正整数,其中文件第i行的正整数为a[i],表示从编号为i的基地到编号为a[i]的基地之间有一条道路,为了更加简洁的描述树状结构的基地群,有a[i]<i。

 

输出格式:

 

输出文件名为output.txt

输出文件仅有一个正整数,表示至少要设立多少个消防局才有能力及时扑灭任何基地发生的火灾。

 

思路:

贪心大法QAQ

f[i]是i的父亲,dep[i]是i的深度

由于题中说输入数据中a[i]<i,故令a[i]为i的父结点,i结点的深度是a[i]结点的深度+1(*)

v[i]表示第i个结点是否被覆盖

类似于一个宽搜吧

                              当所有基地并没有都被覆盖时:

1、取出当前未被覆盖的结点中深度最大的

2、找到该结点父结点的父结点,记为pos,并覆盖。计数器+1

3、枚举所有结点中与pos结点距离不超过2的,并覆盖

                                                然后不断重复以上步骤

代码解释:

 1 #include<iostream>
 2 using namespace std;
 3 int n,cut,ans,x;
 4 bool v[1003];
 5 struct type
 6 {
 7     int dep,fa;
 8 } nod[1003];
 9 
10 int main() 
11 {
12     nod[1].fa=1;
13     cin>>n;
14     for(int i=2;i<=n;i++)
15     cin>>x,nod[x].fa=i,nod[x].dep=nod[i].dep+1;//*
16     while(cut<n)
17     {
18         x=0;
19         for(int i=1;i<=n;i++)
20         if(v[i]==0&&nod[i].dep>nod[x].dep)x=i;//寻找深度最大的结点
21         x=nod[nod[x].fa].fa;
22         if(v[x]==0)cut++;//如果这个点没有被覆盖,那么已覆盖的点数量才能加一
23         ans++,v[x]=1;//答案加一,这个点标记一下
24         
25         for(int i=1;i<=n;i++)
26         if(nod[i].fa==x||nod[nod[i].fa].fa==x||nod[x].fa==i||nod[nod[x].fa].fa==i||nod[i].fa==nod[x].fa)
27         //五种情况被覆盖:分别是:i是x的子结点,i是x子结点的子结点,x是i的子结点,x是i子结点的子结点,i和x是兄弟结点
28         {
29         if(v[i]==0)
30         cut++;
31         v[i]=1;
32         }
33    }
34    cout<<ans<<endl;
35    return 0;//完美!
36 }

 

  

推荐阅读