[HNOI2003][樹上貪心]消防局的設立
阿新 • • 發佈:2020-08-24
(題面)[https://www.luogu.com.cn/problem/P2279]
這道題可以打樹上 \(DP\),但顯然貪心方便
我們貪心地考慮這個問題,一個葉子結點的消防站必然是建在它的爺爺上,才能儘可能多的增加覆蓋的點,所以先跑一遍 \(DFS\) 處理深度,再按深度降序掃描節點即可。
時間複雜度:\(O(n^2)\),可以通過本題。
程式碼:
// no greater than 2 -> father and grandfather # include <iostream> # include <cstdio> # include <queue> # define sp std::pair # define mp std::make_pair # define MAXN 1005 struct edge{ int v, next; }e[MAXN<<1]; struct node{ int dep, fa; }nd[MAXN]; int hd[MAXN], cntE; bool vis[MAXN]; std::priority_queue<sp<int, int>, std::vector<sp<int, int> >, std::less<sp<int, int> > >Q; // pair<dep, id> void AddE(int u, int v); void PreDFS(int now, int fa); void AnsDFS(int now, int dis); int main(){ int n, ans = 0; scanf("%d", &n); for(int i = 2, x; i <= n; i++){ scanf("%d", &x); AddE(i, x); AddE(x, i); } PreDFS(1, 0); int now = Q.top().second; while(Q.size()){ while(vis[now = Q.top().second] && Q.size()){ Q.pop(); } if(Q.empty()){ break; } if(nd[nd[now].fa].fa){ AnsDFS(nd[nd[now].fa].fa, 0); } else{ AnsDFS(1, 0); } ans++; } printf("%d", ans); return 0; } void AnsDFS(int now, int dis){ if(dis > 2){ return; } vis[now] = 1; for(int i = hd[now]; i; i = e[i].next){ AnsDFS(e[i].v, dis+1); } } void PreDFS(int now, int fa){ nd[now] = (node){nd[fa].dep+1, fa}; Q.push(mp(nd[now].dep, now)); for(int i = hd[now]; i; i = e[i].next){ if(e[i].v == fa){ continue; } PreDFS(e[i].v, now); } } void AddE(int u, int v){ e[++cntE] = (edge){v, hd[u]}; hd[u] = cntE; }