【动态规划】 ◆CodeForce 461B◆ Appleman and Tree

◆CodeForce 461B◆

Appleman and Tree


本期语录:不求甚解,如同从叶节点倒回到根节点,只知道解决一道题的路径;回归问题的本质,再加以分类,才能清晰地从根节点找到每一个叶节点,从而解析这一类算法的每一个类型。


□谈一谈感想□

现学先写,我刚听完某两位 dalao 对本题的讲解我就开始写 Blog 了……其实是因为我怕我过久了忘掉(T^T)。因为两位 dalao 边讲边在小声地互相讨论,弄得我一脸懵逼,这篇 Blog 里面可能有一些东西的描述有些问题,感想大家指出!
听完题解过后老师笑呵呵地对我们说这是B题(Oh!Terrible!),我还是不要去 CodeForce 的比赛了 ╮(╯﹏╰)╭


□题目□

Description

Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other vertices are colored white.
Consider a set consisting of k (0 ≤ k < n) edges of Appleman’s tree. If Appleman deletes these edges from the tree, then it will split into (k + 1) parts. Note, that each part will be a tree with colored vertices.
Now Appleman wonders, what is the number of sets splitting the tree in such a way that each resulting part will have exactly one black vertex? Find this number modulo 1000000007 (109 + 7).

Input

The first line contains an integer n (2  ≤ n ≤ 105) — the number of tree vertices.
The second line contains the description of the tree: n - 1 integers p0, p1, …, pn - 2 (0 ≤ pi ≤ i). Where pi means that there is an edge connecting vertex (i + 1) of the tree and vertex pi. Consider tree vertices are numbered from 0 to n - 1.
The third line contains the description of the colors of the vertices: n integers x0, x1, …, xn - 1 (xi is either 0 or 1). If xi is equal to 1, vertex i is colored black. Otherwise, vertex i is colored white.

Output

Output a single integer — the number of ways to split the tree modulo 1000000007 (109 + 7).

Example
Input 1
    3
    0 0
    0 1 1
Output 1
    2
Input 2
    6
    0 1 1 0 4
    1 1 0 0 1 0
Output 2
    1
Input 3
    10
    0 1 2 1 4 4 4 0 8
    0 0 0 1 0 1 1 0 0 1
Output 3
    27

□大致翻译□

描述

zzh有一棵n个顶点的树。每个顶点要么被涂成了黑色,要么被涂成了白色。
我们考虑删掉k条边,那么这棵树就被分成(k +1)部分。同时,要求,每个部分是都存在黑色的点。
现在,聪明的zzh想要知道,有多少种不同的分割方法,使得分割出来的每个部分恰好只有一个黑点。由于答案可能很大,请对(10^9+7)取模。

输入

第一行包含一个整数n(2≤n≤10^ 5),表示树的顶点数量。
第二行包含了树的描述,有个n-1个非负整数P0,P1,…,Pn-2(0≤PI≤i)。其中pi表示第(i + 1)个点和顶点pi有边。树的顶点编号从0到n - 1。
第三行包含顶点的颜色的描述:n个整数X0,X1,…,Xn-1(xi为0或1)。如果xi为等于1,顶点i被着色成黑色。否则,顶点为白色。

输出

输出有多少种不同的分割方法。(注意取模)

copy from Vjudge(https://vjudge.net/problem/CodeForces-461B#author=prayerhgq)


□解析□

不过是dalao 们讨论的结果

1.算法

方法数量……树形结构,这摆明了就是要让我们用树形DP!这是树形DP的类型之一 —— 计数类。

2.建树

我还是一如既往地把树形结构改成了无向图,也就是树形图 —— 原因就是我不想找根!找根真的是一件很麻烦的事,所以定义无向图就可以随意选一个点作为根,所以就要存储一个双向边。这样就需要判断一种情况:
这里写图片描述从此陷入死循环……
所以我们在函数的参数表里要定义一个fa(父亲节点),像这样:DFS(int u,int fa)(好像透露了什么算法),然后判断u的”儿子”是否是fa,如果是,就说明这是双向边。或者你也可以定义一个bool数组vis,判断当前节点是否访问过,也就是一般的图的遍历判重方法,但是既然有树形图的特殊处理方法,为什么不用呢?

3.深度优先搜索

之前的函数名透露了一切……大多数的树形DP都是深度优先搜索的模板。由于当前u的状态需要由它的儿子v的状态倒推回来,所以我们需要先求出v的状态再计算u。

4.动态规划

状态定义(不解释):dp[i][0]:以i为根的子树里全是白色的情况下的方案数;dp[i][1]:以i为根的子树里含有一个黑色节点的情况下的方案数。
那么就会针对u节点的颜色分类:
1. 黑色
u节点是黑色,就说明它的子树(包括u)里不可能全部是白色!所以这种情况dp[u][0]为0。那么现在就需要对u的儿子的颜色进行讨论——若儿子v为根的子树含有一个黑色节点,则它的方案数应该是dp[v][1]、dp[v][0]=0;否则是 dp[v][0]、dp[v][1]=0。综合一下,就是dp[v][1]+dp[v][0]。又根据乘法原理——u的方案总数就是
tree[u].size()i=0(dp[vi][1]+dp[vi][0]) ∏ i = 0 t r e e [ u ] . s i z e ( ) ( d p [ v i ] [ 1 ] + d p [ v i ] [ 0 ] )
2. 白色
这样就很麻烦了……根节点是白色并不意味着它的子树的节点都是白色,所以需要分黑白两类!现在就需要处理儿子v的子树的颜色的情况:
令除v之外的所有儿子都是白色的方案数为F1,那么此情况的方案总数就是 F1*dp[v][1];
令除v以外的所有儿子包含一个黑色的方案总数为F2,那么可以选择隔开此子树,连接子树v,或者隔开子树v,连接另一个子树,此情况的方案总数为 F2*(dp[v][0]+dp[v][1]);
有没有一点奇怪?F1?F2?好像F1就是dp[u][0],F2就是dp[u][1](状态定义)。


□代码□

(不能让你们copy!!除非你们有耐心抄代码……( ̄▽ ̄)/)

老师告诉我们代码要自己理解了再默写( • ̀ω•́ )✧


The End

Thanks for reading!

-Lucky_Glass

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值