神奇脑洞题解——树的最大匹配

(这是道CEOI2007的原题,洛谷上也有哦)

COGS  489

至于为啥没有洛谷链接,实验人怎么能用别人的评测机

其实只是洛谷数据过强,要写高精度的

一句话题面:给定一颗父子关系指明的树,记树上某个点和他的父亲可以形成一对匹配,求这棵树最多可以形成多少匹配,形成这么多种匹配的方案有几种?

【输入格式】

第一行一个数 N ,表示有多少个结点。

接下来 N 行,每行第一个数,表示要描述的那个结点的编号。然后一个数 m ,表示这个结点有 m 个儿子,接下来 m 个数,表示它的 m 个儿子的编号。

【输出格式】

输出两行,第一行为最大匹配数,第二行输出最大匹配方案数。

【输入样例】

7
1 3 2 4 7
2 1 3
4 1 6
3 0
7 1 5
5 0
6 0

【输出样例】

3
4

【数据规模】

N<=1000, 其中 40% 的数据答案不超过 10^7 

看数据就知道要写高精,但COGS可以用long long int 水过去哈

首先考虑第一个问题:最大匹配是多少?

 

这一看就知道是个树形DP,而且每个点上的取值和这个点的状态有关

按照树形DP的套路,状态可以设为在x的子树内,能匹配的最大匹配对数(因为每个点只能和自己的父亲与儿子匹配,因此,各个子树间互不影响)

先大概脑补一下没有上司的舞会这道题,如果没写过的话直接肝这题有点难度哈

按照没有上司的舞会的套路,每个点状态分两种:dp[x][0]和dp[x][1]分别代表当点x不与自己儿子匹配时x内子树匹配最大值和当x参与时的最大值。

那么现在问题就明朗许多了。

先大概思考一下,对于dp[x][0]的计算,因为x点是不用的,因此x的儿子y是否被使用都无所谓,也就是说dp[x][0]=∑max(dp[y][0],dp[y][1]);

这里还可以再加强一波:可以得知dp[y][1]>=dp[y][0];

这个东西比较神奇,但是也可以感性理解一下。假设我们现在有一棵小树,这棵树有两个儿子,两个儿子的子树各是一条链,(实际上这个时候模拟的就是树的最底部)链有多长咱们不管,但是至少我们可以知道,匹配肯定是先选一条边两端的两个节点,但是与其相连的两条边都不能选,贪心可知,叶子节点一定要选,然后这样的话,假设一条长度为3的链,选上树根就可以多得到一对,偶数长度的选上树根也不行,所以说dp[y][1]>=dp[y][0]当且仅当y的子树的链长度均为偶数时取等号。

所以说dp[x][0]=∑dp[y][1];

考虑完dp[x][0],再考虑一下dp[x][1],众所周知,因为x是与自己的某个儿子匹配的,因此可以认为dp[x][1]可以认为是由∑dp[y][1]然后减去min(dp[y][1]-dp[y][0])再+1得到的

这里可以将求dp[x][0]和求dp[x][1]合在一起(因为dp[x][0]就是dp[y][1]之和)

提一句,维护顺序是先维护dp[x][1]再维护dp[x][0]这样可以有效利用之前计算的信息

下面的代码中,dp[x][0]是代表前i-1个子树dp[y][1]之和,而dp[x][1]已经开始维护第i个子树的影响了。

if(dp[x][1
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值