树形dp

树形dp

题号:Codeforces 461B

题意:

输入 n ,表示有一个 n 个节点的树;

输入 n-1 个数 P[0] ~ P[n-1],p[i]表示无向边将 i+1 和 P[i] 连接起来

输入 n 个数 ,表示每个节点的颜色,0为白色,1为黑色

要切断 k 条边变成 k 个连通分量,每个分量有且只有一个方案数,求有多少种分割方案;

思路:

从根节点向下递归,上层利用回溯计算结果;

实在搞不懂,先记录一下

撸代码:

 1#include<stdio.h>
2#include<string.h>
3#define N 101000
4struct Edge
5{

6    int to,nex;
7} edge[N*3];
8int cnt,n;
9int head[N];/**链表头结点*/
10int c[N];/**标记节点黑白*/
11long long dp[N][2];
12void init()
13
{
14    memset(head,-1,sizeof(head));
15    cnt=0;
16}
17
18void addEdge(int u,int v)
19
{
20    edge[cnt].to=v;
21    edge[cnt].nex=head[u];
22    head[u]=cnt++;
23
24    edge[cnt].to=u;
25    edge[cnt].nex=head[v];
26    head[v]=cnt++;
27
28}
29long long mod=1000000007;
30void dfs(int u,int fa)
31
{
32
33    dp[u][c[u]]=1;
34    for(int i=head[u]; i!=-1; i=edge[i].nex)
35    {
36        int v=edge[i].to;
37        if(v==fa)
38            continue;
39        dfs(v,u);/**从上往下遍历 ,利用回溯*/
40
41        /**dp 数组含义:以U为根,当前连通块有黑点 [1] 或没有黑点 [0] 方案数*/
42
43        /**子树和根都有黑点,则边剪掉;根为黑点但子树无黑点,保留边;根无黑点而子树有黑点*/
44        dp[u][1]=(dp[u][1]*dp[v][1]%mod+dp[u][0]*dp[v][1]%mod+dp[u][1]*dp[v][0]%mod)%mod;
45
46        /**没有黑点就要保留所有*/
47        dp[u][0]=(dp[u][0]*dp[v][0]%mod+dp[u][0]*dp[v][1]%mod)%mod;
48    }
49
50}
51
52int main()
53
{
54
55    scanf("%d",&n);
56    init();
57    int v;
58    for(int i=1; i<n; i++)
59    {
60        scanf("%d",&v);
61        addEdge(v,i);
62    }
63
64    for(int i=0; i<n; i++)
65    {
66        scanf("%d",&c[i]);
67    }
68    dfs(0,0);
69    printf("begin: ");
70    for(int i=0;i<n;i++)
71    {
72        printf("i=%d : %lld %lld ",i,dp[i][0],dp[i][1]);
73    }
74    printf("%lld ",dp[0][1]);
75    return 0;
76}
原文地址:https://www.cnblogs.com/HappyKnockOnCode/p/12853078.html