树形 DP 问题

树形 \(dp\) 问题

  • 最小点覆盖

问题:

给定一颗有 \(n\) 个点的有根树,从这 \(n\) 个点中选出尽量少的点,使得所有边都与取出来的点相连。

分析:

考虑一条边,它两端的节点必定有一个在所选点集中,可以考虑 \(dp\) :

\(f_{u,0}\) 表示以 \(u\) 为根的子树中, \(u\) 不在点覆盖集中所需要选取的最小点数; \(f_{u,1}\) 表示以 \(u\) 为根的子树中, \(u\) 在点覆盖集中所需要选取的最小点数。

接下来考虑转移 (其中 \(v\)\(u\) 的儿子):

对于 \(f_{u,0}\) ,因为 \(u\) 不选取,则 \(u\) 的儿子一定要取,所以 \(f_{u,0}=\sum f_{v,1}\)

对于 \(f_{u,1}\) , 因为 \(u\) 要选取,则 \(u\) 的儿子可选可不选,所以 \(f_{u,1} = 1+\sum min(f_{v,0},f_{v,1})\)

设根节点为 \(root\) ,则最后答案为 \(min(f_{root,0},f_{root,1})\)

int f[MAXN][2];
void Dfs(int u,int fa)
{
	f[u][0]=0;f[u][1]=1;
	for(int v:G[u])
	{
		if(v==fa) continue;
		Dfs(v,u);
		f[u][0]+=f[v][1];
		f[u][1]+=min(f[v][0],f[v][1]);
	}
}
  • 最大独立集

问题:

给定一棵有 \(n\) 个点的树,从 \(n\) 个点中选出尽量多的点,使得两两之间没有连边。

分析:

同上,考虑一条边,它两端的点不能被同时选取,那么考虑 \(dp\)

\(f_{u,0}\) 表示以 \(u\) 为根的子树中 \(u\) 不在最大独立集中最多可以选多少点, \(f_{u,1}\) 表示以 \(u\) 为根的子树中 \(u\) 在最大独立集中最多可以选多少点。

接下来考虑转移:

对于 \(f_{u,0}\) ,因为 \(u\) 不选,所以 \(u\) 的儿子可选可不选,则 \(f_{u,0}=\sum max(f_{v,0},f_{v,1})\)

对于 \(f_{u,1}\) ,因为 \(u\) 要选,所以 \(u\) 的儿子一定不能选,则 \(f_{u,1}=1+\sum f_{v,0}\)

则最后的答案为 \(max(f_{root,0},f_{root,1})\)

int f[MAXN][2];
void Dfs(int u,int fa)
{
	f[u][0]=0;f[u][1]=1;
	for(int v:G[u])
	{
		if(v==fa) continue;
		Dfs(v,u);
		f[u][0]+=max(f[v][0],f[v][1]);
		f[u][1]+=f[v][0];
	}
}
  • 最小支配集

问题:

给定一棵 \(n\) 个点的树,从 \(n\) 个点中选取尽量少的点,使得任意一个不在支配集中的点都和一个在支配集中的点有连边。

分析:

我们设 \(f_{u,0}\) 表示 \(u\) 在支配集中至少要选几个点,简称被自己支配。

\(f_{u,1}\) 表示 \(u\) 不在支配集中,而 \(u\) 的儿子在支配集中至少要选几个点,简称被儿子支配。

\(f_{u,2}\) 表示 \(u\) 不在支配集中,而 \(u\) 的父亲在支配集中至少要选几个点,简称被父亲支配。

接下来考虑转移:

对于 \(f_{u,0}\) ,因为 \(u\) 选了,那么 \(u\) 的儿子可选可不选,所以 \(f_{u,0}=1+\sum min(f_{v,0},f_{v,1},f_{v,2})\)

对于 \(f_{u,1}\) ,因为 \(u\) 不选,而至少要有一个 \(u\) 的儿子要选,所以我们枚举选的儿子 \(v_i\) ,设 \(x\)\(u\) 的儿子数,则其余的儿子为 \(v_j(1 \leq i \leq x\ ,\ i \not= j)\) ,则 \(f_{u,1}=f_{v_i,0}+\sum min(f_{v_j,0},f_{v_j,1})\)

对于 \(f_{u,2}\) ,因为 \(u\) 靠了 \(u\) 的父亲支配,则 \(u\) 的儿子只能靠自己或者自己的儿子。则 \(f_{u,2}=\sum min(f_{v,0},f_{v,1})\)

则最后的答案为 \(min(f_{root,0},f_{root,1})\)

void Dfs(int u,int fa)
{
	int sum=0;
	for(int v:G[u])
	{
		if(v==fa) continue;
		Dfs(v,u);
		sum+=min(f[v][0],f[v][1]);
	}
	f[u][0]=1;f[u][1]=INF;f[u][2]=0;
	for(int v:G[u])
	{
		if(v==fa) continue;
		f[u][0]+=min(min(f[v][0],f[v][1]),f[v][2]);
		f[u][1]=min(f[u][1],sum-min(f[v][0],f[v][1])+f[v][0]);
		f[u][2]+=min(f[v][0],f[v][1]);
	}
}
posted @ 2024-09-26 00:05  zhln  阅读(20)  评论(0)    收藏  举报