洛谷题解,原链接:link。
思路简述
本题是一道基础树形 Dp
。
定义 D p i , 0 Dp_{i,0} Dpi,0 代表第 i i i 个节点涂白色的方案数;
同理 D p i , 1 Dp_{i,1} Dpi,1 代表第 i i i 个节点涂黑色的方案数。
接着是状态转移方程。
首先我们所采用的遍历树的方法是后序遍历,这很好理解;
接着根据题意可以知道 D p i , 0 Dp_{i,0} Dpi,0 由 D p j , 0 Dp_{j,0} Dpj,0 和 D p j , 1 Dp_{j,1} Dpj,1 转移而来,其中 j j j 是 i i i 的子节点;
进一步推出 D p i , 1 Dp_{i,1} Dpi,1 仅由 D p j , 0 Dp_{j,0} Dpj,0 转移而来。
更进一步的,用乘法原理可以得到状态转移方程为:
D
p
i
,
0
=
∏
j
∈
E
d
g
e
i
D
p
j
,
1
+
D
p
j
,
0
Dp_{i,0}=\prod_{j\in Edge_i}Dp_{j,1}+Dp_{j,0}
Dpi,0=j∈Edgei∏Dpj,1+Dpj,0
D
p
i
,
1
=
∏
j
∈
E
d
g
e
i
D
p
j
,
0
Dp_{i,1}=\prod_{j\in Edge_i}Dp_{j,0}
Dpi,1=j∈Edgei∏Dpj,0
其中 E d g e i Edge_i Edgei 表示 i i i 的子节点。
思路部分结束。
代码与易错点
先放代码:
#include <bits/stdc++.h>
#define ll long long
#define Mod 1000000007
using namespace std;
ll a[100005];
ll Dp[100005][2];
ll n;
vector<ll> Edge[100005];
void dfs(ll fa, ll step) { //树形Dp
Dp[step][1] = Dp[step][0] = 1;
for (auto x : Edge[step]) {
if (x == fa) continue; //切记不可删
dfs (step, x);
Dp[step][0] = (Dp[step][0] * (Dp[x][1] + Dp[x][0]) % Mod) % Mod; //状态转移
Dp[step][1] = (Dp[step][1] * Dp[x][0]) % Mod;
}
}
int main() {
cin >> n;
for (ll i = 1; i < n; i++) {
ll fa, son;
cin >> fa >> son;
Edge[fa].push_back(son); //双向建树
Edge[son].push_back(fa);
}
dfs(0, 1);
cout << (Dp[1][1] + Dp[1][0]) % Mod; //一定要模
return 0;
}
易错点
- 忘开 l o n g l o n g long~long long long。
- 忘取模。
- 输出成
(Dp[n][1] + Dp[n][0]) % Mod
(本人在这里卡了好久…)。 - 忘记双向建树。