樹上染色(樹形dp)

cn是大帅哥886發表於2024-08-23
第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; 
} 

  

相關文章