【洛谷P4084】Barn Painting【樹形DP】
阿新 • • 發佈:2018-11-09
題目大意:
題目連結:https://www.luogu.org/problemnew/show/P4084
一棵
個節點的樹上有
個點已被染色。求將這棵樹染成三種顏色且相鄰的節點顏色不同的方案數。
思路:
肯定是樹形DP啊。設
表示第
個節點顏色為
的時候以
為根的方案數。
那麼考慮所有
的子樹
,由於這些子樹肯定互不關聯,所以任意一個子樹對其它子樹就沒有影響。那麼很明顯的,第一個子樹的所有情況可以和第二個子樹的所有情況都匹配,所以就有
種方案。然後加入第三顆子樹,就有
種方法,以此類推。。。
所以就有:
別忘了要取模
。
最終答案為
程式碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 100100
#define MOD 1000000007ll
#define ll long long
using namespace std;
int n,m,tot,head[N],color[N];
ll f[N][4];
bool vis[N][4]; //記錄是否訪問過這個節點
struct edge
{
int next,to;
}e[N*2];
void add(int from,int to)
{
tot++;
e[tot].to=to;
e[tot].next=head[from];
head[from]=tot;
}
ll dp(int x,int col,int fa)
{
if (color[x]&&col!=color[x])
return 0;
if (vis[x][col]) return f[x][col]; //剪枝
vis[x][col]=true;
ll ans=0;
f[x][col]=1;
for (int i=head[x];~i;i=e[i].next)
if (e[i].to!=fa)
{
ans=0;
for (int j=1;j<=3;j++) //列舉每個顏色
if (j!=col) //顏色要不同
ans=(ans+dp(e[i].to,j,x))%MOD;
f[x][col]=(f[x][col]*ans)%MOD;
}
return f[x][col];
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
int x,y;
for (int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for (int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
color[x]=y;
}
dp(1,1,-1);
dp(1,2,-1);
dp(1,3,-1);
cout<<(f[1][1]+f[1][2]+f[1][3])%MOD;
return 0;
}