[洛谷]P4084 [USACO17DEC]Barn Painting (#樹形dp)

題意翻譯

題意:給定一顆N個節點組成的樹,3種顏色,其中K個節點已染色,要求任意兩相鄰節點顏色不同,求合法染色方案數。 翻譯貢獻者:Il_ItzABC_lI

題目描述

Farmer John has a large farm with NN barns (1 \le N \le 10^51≤N≤105), some of which are already painted and some not yet painted. Farmer John wants to paint these remaining barns so that all the barns are painted, but he only has three paint colors available. Moreover, his prize cow Bessie becomes confused if two barns that are directly reachable from one another are the same color, so he wants to make sure this situation does not happen.

It is guaranteed that the connections between the NN barns do not form any 'cycles'. That is, between any two barns, there is at most one sequence of connections that will lead from one to the other.

How many ways can Farmer John paint the remaining yet-uncolored barns?

輸入格式

The first line contains two integers NN and KK (0 \le K \le N0≤K≤N), respectively the number of barns on the farm and the number of barns that have already been painted.

The next N-1N−1 lines each contain two integers xx and yy (1 \le x, y \le N, x \neq y1≤x,y≤N,x≠y) describing a path directly connecting barns xx and yy.

The next KK lines each contain two integers bb and cc (1 \le b \le N1≤b≤N, 1 \le c \le 31≤c≤3) indicating that barn bbis painted with color cc.

輸出格式

Compute the number of valid ways to paint the remaining barns, modulo 10^9 + 7109+7, such that no two barns which are directly connected are the same color.

輸入輸出樣例

輸入 #1複製

4 1
1 2
1 3
1 4
4 3

輸出 #1複製

8

思路

樹形dp好題。和沒有喪屍的舞會那題有點像。

令dp[i][j]爲在節點i染第j種顏色的方案數,把1號節點看成根。

由於相鄰的點顏色不能相同,所以轉移的時候只能由顏色不同的轉移過來。由乘法原理,當前節點i的方案數應爲其子樹方案數的乘積。

dp[i][1]=dp[i][1]×(dp[son][2]+dp[son][3])

dp[i][2]=dp[i][2]×(dp[son][1]+dp[son][3])

dp[i][3]=dp[i][3]×(dp[son][1]+dp[son][2])

對於一個最初沒有塗色的點i,剛遍歷到的時候設置點i的初始值dp[i][1]=dp[i][2]=dp[i][3]=1。如果點i已經被上色了,那麼只有被上的顏色的數組才能爲1。

最後答案就是dp[root][1]+dp[root][2]+dp[root][3]了。

#include <stdio.h>
#include <iostream>
#define ll long long int 
#define mod 1000000007
#define maxn 100001
using namespace std;
ll n,m,s,cnt,head[maxn],color[maxn];
ll dp[maxn][4];
bool vis[maxn];
struct node
{
	ll nxt,to;
}e[maxn<<1];
inline void add(int u,int v)//前向星存圖 
{
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	head[u]=cnt;
}
void dfs(int i)
{
	vis[i]=1;
	if(color[i])//如果該節點i已經上過色 
	{
		dp[i][color[i]]=1;//該種顏色都有,其他2種方案數爲0 
	}
	else//如果沒上過色 
	{
		dp[i][1]=1;//其他顏色都有可能被上 
		dp[i][2]=1;
		dp[i][3]=1;
	}
	for(register ll j=head[i];j;j=e[j].nxt)//找節點i的子節點 
	{
		int v(e[j].to);
		if(vis[v]==0)
		{
			dfs(v);
			dp[i][1]=dp[i][1]*((dp[v][2]+dp[v][3])%mod)%mod;
			dp[i][2]=dp[i][2]*((dp[v][1]+dp[v][3])%mod)%mod;
			dp[i][3]=dp[i][3]*((dp[v][1]+dp[v][2])%mod)%mod;
		}
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	register ll i,j,u,v;
	cin>>n>>m;
	for(i=1;i<=n-1;i++)
	{
		cin>>u>>v;
		add(u,v);//無向 
		add(v,u);
	}
	for(i=1;i<=m;i++)
	{
		cin>>u>>v;
		color[u]=v;//u爲節點,v爲顏色種類 
	}
	dfs(1);//令節點1爲根節點 
	cout<<(dp[1][1]+dp[1][2]+dp[1][3])%mod<<endl;
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章