树上染色(树形dp)
第2题 树上染色 查看测评数据信息
有一个n个节点的树,每个节点染色成黑色或白色,要求任意相邻的节点不能都是黑色,问一共有多少种染色方案,答案对1000000007取模。
输入格式
第一行一个整数n
接下来n-1行,每行两个整数u,v,表示u到v有一条边。
1<=n<=1e5,1<=u,v<=n
输出格式
一个整数
输入/输出例子1
输入:
3
1 2
2 3
输出:
5
输入/输出例子2
输入:
4
1 2
1 3
1 4
输出:
9
样例解释
无
求方案数时注意分清楚加法原理和乘法原理!!!最好推算一下
还是比较简单,但是我考场上没切出来!!!!!!可恶了。
这题一看就是树形dp,而不是换根。
考虑记 f[i][0/1],表示以i为子树,i节点染(0黑1白)时染色方案总数

注意一下,因为这里是求方案总数,肯定是乘法原理
理解一下:假设u的第一个子树v1,选了1个点,那么u的第二个子树v2,可以选cnt[v2]个点,然后v1可以选2个点,v2继续选cnt[v2]
也就是两棵子树的选择方法不单单相加,他俩有一处不同即可,也就是乘法原理
考场上就是这里出错了!
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5, Mod=1000000007;
int n, u1, v1, root=0, rd[N];
vector<int> a[N];
long long f[N][5];
void dfs(int u, int fa)
{
f[u][0]=f[u][1]=1;
for (int i=0; i<a[u].size(); i++)
{
int v=a[u][i];
if (v==fa) continue;
dfs(v, u);
f[u][0]=(f[u][0]*f[v][1])%Mod;
f[u][1]=(f[u][1]*(f[v][1]+f[v][0]))%Mod;
}
}
int main()
{
scanf("%d", &n);
for (int i=1; i<n; i++)
{
scanf("%d%d", &u1, &v1);
a[u1].push_back(v1);
a[v1].push_back(u1);
rd[v1]++;
}
for (int i=1; i<=n; i++)
if (!rd[i])
{
root=i;
break;
}
dfs(root, -1);
printf("%lld", (f[root][0]+f[root][1])%Mod);
return 0;
}

浙公网安备 33010602011771号