树上染色(树形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; }