1. 程式人生 > >Luogu2279[HNOI2003] 消防局的設立

Luogu2279[HNOI2003] 消防局的設立

原題連結:https://www.luogu.org/problemnew/show/P2279

消防局的設立

題目描述

2020 2020 年,人類在火星上建立了一個龐大的基地群,總共有 n n 個基地。起初為了節約材料,人類只修建了 n

1 n-1 條道路來連線這些基地,並且每兩個基地都能夠通過道路到達,所以所有的基地形成了一個巨大的樹狀結構。如果基地 A A 到基地 B
B
至少要經過 d d 條道路的話,我們稱基地 A A 到基地 B
B
的距離為 d d

由於火星上非常乾燥,經常引發火災,人類決定在火星上修建若干個消防局。消防局只能修建在基地裡,每個消防局有能力撲滅與它距離不超過 2 2 的基地的火災。

你的任務是計算至少要修建多少個消防局才能夠確保火星上所有的基地在發生火災時,消防隊有能力及時撲滅火災。

輸入輸出格式
輸入格式:

輸入檔名為 i n p u t . t x t input.txt

輸入檔案的第一行為 n ( n < = 1000 ) n (n<=1000) ,表示火星上基地的數目。接下來的 n 1 n-1 行每行有一個正整數,其中檔案第i行的正整數為 a [ i ] a[i] ,表示從編號為 i i 的基地到編號為 a [ i ] a[i] 的基地之間有一條道路,為了更加簡潔的描述樹狀結構的基地群,有 a [ i ] < i a[i]<i

輸出格式:

輸出檔名為 o u t p u t . t x t output.txt

輸出檔案僅有一個正整數,表示至少要設立多少個消防局才有能力及時撲滅任何基地發生的火災。

輸入輸出樣例
輸入樣例#1:

6
1
2
3
4
5

輸出樣例#1:

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();}