HNOI2003 消防局的設立
阿新 • • 發佈:2018-10-19
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‘) usingnamespace 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 消防局的設立