[ JLOI 2016 / SHOI 2016 ] 侦查守卫题解

首先,我们可以定义状态 \(f_{u, j}\)\(g_{u, j}\)

\(f_{u, j}\) 表示点 \(u\) 及其子树的所有特殊点都被覆盖,并且还能向上扩展至少 \(j\) 层的最小花费。

\(g_{u, j}\) 表示已 \(u\) 为子树的根,\(j\) 层以下被完全覆盖, \(j\) 层以内状态随意的最小花费。

假设点 \(u\) 为父节点,点 \(v\) 为子节点,来考虑状态转移方程。

\(f_{u, j}=\min(f_{u, j}+g_{v,j},g_{u,j+1}+f_{v,j+1})\)

\(g_{u, j}=\Sigma g_{v, j-1}\)

另外我们可以从状态的定义中发现:

因为 \(f_{u, j}\) 是还能向上扩展至少 \(j\) 层,所以又有 \(f_{u, j}=\min(f_{u,j},f_{u,j+1})\)

\(g_{u, j}\)\(j\) 层以内状态是不确定的,所以 \(g_{u, j}=\min(g_{u,j}.g_{u,j-1})\)

有了状态转移,我们来考虑初始状态的值。

如果这一个点需要被观察,如果只包含这一个点就必须放置一个侦查守卫,那么 \(f_{u,0}=g_{u,0}=w_u\)

其他点就不是一定要放,所以 \(f_{u,0}=g_{u,0}=0\)

还需要设置边界 \(f_{u,d+1}=\infty\)\(f_{u,d}\) 进行限制

并且 \(f_{u,j}\) 都需要赋值为 \(w_u\)

由定义不难得知答案为 \(f_{1,0}\)

void dfs(int u, int fa) {
	if (vis[u])
		f[u][0] = g[u][0] = w[u];
	for (int i = 1; i <= d; i++)
		f[u][i] = w[u];
	f[u][d + 1] = INF;
	for (int i = head[u]; i; i = nxt[i]) {
		int v = ver[i];
		if (v != fa) {
			dfs(v, u);
			for (int j = d; j >= 0; j--)
				f[u][j] = min(f[u][j] + g[v][j], g[u][j + 1] + f[v][j + 1]);
			for (int j = d; j >= 0; j--)
				f[u][j] = min(f[u][j], f[u][j + 1]);
			g[u][0] = f[u][0];
			for (int j = 1; j <= d + 1; j++)
				g[u][j] += g[v][j - 1];
			for (int j = 1; j <= d + 1; j++)
				g[u][j] = min(g[u][j], g[u][j - 1]);
		}
	}
}
posted @ 2023-01-10 20:07  zhou_ziyi  阅读(33)  评论(0)    收藏  举报