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

HNOI2003 消防局的設立

rep org cst har clu space str noi2003 algorithm

傳送門

這道題似乎是夾克老爺的憤怒那道題的弱化版……?這次的距離是固定為2的。

我們首先考慮一下只有一條鏈的情況,這個誰都會,就是每隔2k(k為給定距離)個點放一個,就是這樣貪心。樹也可以用這種貪心法來求解,我們從葉子節點往上DP,每次用dp[i]表示這個點還能往上控制距離為多少的點,如果當前的dp值為-2的話,就新建立一個消防局,並把dp值改為2,同時還要記錄當前點所有子節點dp值的最大和最小值,如果二者和大於零,那就說明這個點可以被自己的某個子節點控制,那麽dp值就是最大值-1,否則的話,dp值就是最小值-1。

這樣直接dp即可,最後到根節點的時候,如果dp值小於0,那麽還需要多建立一個消防局。

看一下代碼。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#include<queue>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar(‘\n‘)

using
namespace std; typedef long long ll; const int M = 100005; const int INF = 1000000009; int read() { int ans = 0,op = 1; char ch = getchar(); while(ch < 0 || ch > 9) { if(ch == -) op = -1; ch = getchar(); } while(ch >= 0 && ch <= 9) { ans *= 10; ans
+= ch - 0; ch = getchar(); } return ans * op; } struct edge { int next,to; }e[M]; int n,head[M],ecnt,dp[M],x,y,ans; void add(int x,int y) { e[++ecnt].to = y; e[ecnt].next = head[x]; head[x] = ecnt; } void dfs(int x,int fa) { int minn = INF,maxn = -INF; for(int i = head[x];i;i = e[i].next) { if(e[i].to == fa) continue; dfs(e[i].to,x); minn = min(minn,dp[e[i].to]); maxn = max(maxn,dp[e[i].to]); } if(minn == INF) dp[x] = -1; else if(minn <= -2) ans++,dp[x] = 2; else if(minn + maxn > 0) dp[x] = maxn - 1; else dp[x] = minn - 1; } int main() { n = read(); rep(i,2,n) x = read(),add(i,x),add(x,i); dfs(1,1); if(dp[1] < 0) ans++; printf("%d\n",ans); return 0; }

HNOI2003 消防局的設立