[HNOI2003] 消防局的設立
阿新 • • 發佈:2021-08-24
[HNOI2003] 消防局的設立
樹形 \(DP\) , 其實這個題的貪心非常好想也非常好寫, 但是為了練習樹形 \(DP\) , 嘶~
這個題不算難, 但是我寫了好久, 原因是寫錯下標了...
設狀態 \(f[x][0/1/2/3/4]\) 表示以 \(x\) 為根節點, 覆蓋到向上 \(2/1/0/-1/-2\) 層的最小消防站數.
轉移稍微麻煩一點, 設 \(y\) 為 \(x\) 的兒子, 如果我們能夠覆蓋到向上 \(2\) 層, 那麼我們當前位置一定有一個消防站, 為了讓消防站數最少, 那麼我們下面 \(4\) 層沒有消防站, 所以我們從 \(f[y][4]\) 轉移過來, \(f[x][0] = \sum f[y][4] + 1\)
\(code:\)
看不見我看不見我看不見我#include <bits/stdc++.h> using namespace std; typedef long long ll; int read() { int x = 0, f = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = getchar(); } while (isdigit(ch)) { x = (x << 1) + (x << 3) + (ch ^ 48); ch = getchar(); } return x * f; } const int N = 1005, inf = 1 << 30; int n, f[N][5]; int tot, to[N], nxt[N], head[N]; void add(int u, int v) { to[++tot] = v, nxt[tot] = head[u], head[u] = tot; } void dfs(int x) { int f1 = -inf, f2 = -inf; f[x][0] = 1; for (int i = head[x]; i; i = nxt[i]) { int y = to[i]; dfs(y); f[x][0] += f[y][4]; f[x][1] += f[y][3]; f[x][2] += f[y][2]; f[x][3] += f[y][2]; f[x][4] += f[y][3]; f1 = max(f1, f[y][3] - f[y][0]); f2 = max(f2, f[y][2] - f[y][1]); } if (!head[x]) f[x][1] = f[x][2] = 1; else f[x][1] -= f1, f[x][2] -= f2; for (int i = 1; i < 5; i++) f[x][i] = min(f[x][i], f[x][i - 1]); } int main() { n = read(); for (int i = 2; i <= n; i++) { int u = read(); add(u, i); } dfs(1); printf("%d", f[1][2]); return 0; }