第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白)時染色方案總數
轉移就很好搞了
f[u][0]*=f[v][1]
f[u][0]*=(f[v][1]+f[v][0])
注意一下,因為這裡是求方案總數,肯定是乘法原理
理解一下:假設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; }