UESTC 887 方伯伯的儿童节 --树形DP

时间:2021-05-22 12:42:05

定义:

1.dp[u][1]表示u这个点设立糖果发放点且u这棵子树满足条件时的最少糖果点数

2.dp[u][0]表示u这个点不设立发放点且u这棵子树满足条件时的最少糖果点数

设v1,v2……vn为u的子节点,则转移方程:

dp[u][1]= sum(min(dp[vi][1],dp[vi][0]) )+1;

dp[u][0]=sum(dp[vi][1]);

由于还要记录方案数,做一个num[][]数组随着dp[][]一起转移:

num[u][1]表示u这个点设立糖果发放点的最少点数方案。

num[u][0]表示u这个点不设立糖果发放点的最少点数方案。

分三种情况:

1.dp[v][0]<dp[v][1]:  dp[u][1] += dp[v][0]     num[u][1] *= num[v][0]

2.dp[v][0]=dp[v][1]:  dp[u][1] += dp[v][0/1]  num[u][1] *= (num[v][1]+num[v][0])

3.dp[v][0]>dp[v][1]:  dp[u][1] += dp[v][1]     num[u][1] *= num[v][1]

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define Mod 1000000007
using namespace std;
#define N 100007 int dp[N][],num[N][];
vector<int> G[N]; void dfs(int u,int fa)
{
dp[u][] = ;
dp[u][] = ;
num[u][] = num[u][] = ;
for(int i=;i<G[u].size();i++)
{
int v = G[u][i];
if(v == fa)
continue;
dfs(v,u);
dp[u][] += dp[v][];
num[u][] *= num[v][]; //num[u][0]
num[u][] %= SMod;
if(dp[v][] < dp[v][])
{
dp[u][] += dp[v][];
num[u][] *= num[v][];
}
else if(dp[v][] > dp[v][])
{
dp[u][] += dp[v][];
num[u][] *= num[v][];
}
else
{
dp[u][] += dp[v][];
num[u][] *= (num[v][]+num[v][]);
}
num[u][] %= SMod; //num[u][1]
}
} void init()
{
for(int i=;i<=;i++)
G[i].clear();
} int main()
{
int t,n,i,x,y;
scanf("%d",&t);
while(t--)
{
init();
scanf("%d",&n);
for(i=;i<n-;i++)
{
scanf("%d%d",&x,&y);
G[x].push_back(y);
G[y].push_back(x);
}
dfs(,-);
if(dp[][] < dp[][])
printf("%d %d\n",dp[][],num[][]);
else if(dp[][] > dp[][])
printf("%d %d\n",dp[][],num[][]);
else
printf("%d %d\n",dp[][],(num[][]+num[][])%SMod);
}
return ;
}