您的位置:首页 > 移动开发

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

2018-02-07 21:55 555 查看

◆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=0tree[u].size()(dp[vi][1]+dp[vi][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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  树形DP CodeForce