树形DP例题讲解

T1

在这里插入图片描述
分析:
我们可以很清晰的发现,这是一道树形dp的问题,找最短链的方法很简单,就是数叶节点的个数,然后就可以考虑如何去DP了。

我们先从下面这张图来分析:
在这里插入图片描述
因为要求链的一个端点必须是另一个端点的祖先,因此可以论证,链的数量等于叶子结点的数量,因此需要求的只有最小代价。
定义dp[u][j]为考虑子树u,并且点u所属的链当前的异或和为j时的最小代价。对每一个点枚举与它相连的子节点即可。
v — u 的儿子结点
w[u]— 结点 u 的标志值
mini[u]— 以结点 u 为树根开始编译文件的最小代价,mini[1]即为最终答案。
minisum—当前结点所有儿子结点的最小代价总和
dp[u][j]—以结点 u 所属的链当前的异或值和为 j 时的最小代价
动态转移方程:
dp[u][jw[u]]=min(dp[u][jw[u]],minisum-mini[v]+dp[v][j]) 0<=j<=255
mini[u] = min(mini[u],dp[u][j]+j),0<=j<=255

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int u[40010],v[40010],first[40010],nex[40010];
int n,cnt=0,ans=0;
int p[20010];
int dp[20010][260];
int mini[20010];
void add(int x,int y) //建图,注意是双向
{
	cnt++;
	u[cnt]=x;v[cnt]=y;
	nex[cnt]=first[x];
	first[x]=cnt;
}
void dfs(int me,int father)
{
	int t=0; //表示儿子节点的个数
	
	for(int i=first[me];i!=-1;i=nex[i])
	{
		if(v[i]!=father)
		{
			dfs(v[i],me);
			t++;
		}
	}
	if(t==0) //叶节点
	{
		ans++;
		mini[me]=p[me];
		dp[me][p[me]]=0;
		return;
	}
	else
	{
		int s=0; //和
		for(int j=first[me];j!=-1;j=nex[j])
			if(v[j]!=father)
				s+=mini[v[j]]; 
		for(int j=first[me];j!=-1;j=nex[j])
			if(v[j]!=father)
				for(int i=0;i<=255;i++)
					dp[me][i^p[me]]=min(s-mini[v[j]]+dp[v[j]][i],dp[me][i^p[me]]);
			
		for(int i=0;i<=255;i++)
			mini[me]=min(mini[me],dp[me][i]+i);
		return;
	}
}
int main()
{
	freopen("compiler.in","r",stdin);
	freopen("compiler.out","w",stdout);
	memset(first,-1,sizeof(first));
	memset(nex,-1,sizeof(nex));
	memset(dp,0x7f,sizeof(dp));
	memset(mini,0x7f,sizeof(mini));
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%02x",&p[i]);
	for(int i=1,x,y;i<n;i++)
	{
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	dfs(1,0);
	cout<<ans<<' '<<mini[1];
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值