P2279 [HNOI2003]消防局的设立

P2279 HNOI2003消防局的设立

设 f[u][0] 表示将 u 的子树 和 u的二级祖先都被覆盖 的最小代价
设 f[u][1] 表示将 u 的子树 和 u的一级祖先都被覆盖 的最小代价
设 f[u][2] 表示将 u 的子树 覆盖 的最小代价
设 f[u][3] 表示将 u 的一级儿子覆盖 的最小代价
设 f[u][4] 表示将 u 的二级儿子覆盖 的最小代价
其中, 上面的状态包含下边的状态,进而 f[u][0]≥f[u][1]≥f[u][2]≥f[u][3]≥f[u][4]

转移: \(f_{u,0}=\sum f_{v,4}\) (覆盖到二级祖先必然是消防站,于是子节点可以任意)
<未写完>

点击查看代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
const int N = 1005, M = N << 1;
int n, h[N], e[M], nxt[M], idx;
int f[N][5];
void add(int a, int b) {
	e[++ idx] = b, nxt[idx] = h[a], h[a] = idx;
}
void dfs(int u) {
	f[u][0] = 1;
	for(int i = h[u], v; i; i = nxt[i])
		dfs(v = e[i]), f[u][0] += f[v][4], f[u][3] += f[v][2], f[u][4] += f[v][3];
	if(!h[u]) f[u][1] = f[u][2] = 1;
	else {
		f[u][1] = f[u][2] = 0x3f3f3f3f;
		for(int i = h[u], v; i; i = nxt[i]) {
			v = e[i]; int f0 = f[v][0], f1 = f[v][1];
			for(int j = h[u], k; j; j = nxt[j])
				if(i != j) k = e[j], f0 += f[k][3], f1 += f[k][2];
			f[u][1] = std::min(f[u][1], f0), f[u][2] = std::min(f[u][2], f1);
		}
	}
	for(int i = 1; i <= 4; i ++) f[u][i] = std::min(f[u][i], f[u][i-1]);
}
int main() {
	scanf("%d", &n);
	for(int i = 2, fa; i <= n; i ++)
		scanf("%d", &fa), add(fa, i);
	dfs(1), printf("%d\n", f[1][2]);
	return 0;
}
posted @ 2022-10-13 16:30  azzc  阅读(20)  评论(0编辑  收藏  举报