[笔记][题解]树形DP&lgP4084
[笔记][题解]树形\(DP\)&\(lgP4084\)
原题链
题目分析
一眼看过去是给定几个限制求方案数,那么肯定联想到\(DP\),而且给出的是树形结构,那么就是一道树形\(DP\)的题。
树形\(DP\)
那么先来总结一下树形\(DP\)的一般规律,首先关于状态转移方程,一般是设\(dp[i][j]\)表示的是以\(i\)为根的子树,有\(j\)或者更多的限制就用多维数组。那么如何求解呢?一般考虑两种思路:\(1.\)先把所有的子树都搜索完再来更新父亲节点的信息\(\&\)答案。\(2.\)而如果是树上背包问题,则需要一个一个的更新。
例题\(lgP4084\)
这道题很容易得出状态转移方程:设\(dp[i][j]\)表示节点\(i\)涂第\(j\)种颜色的方案数,那么转移就从与它相连的颜色不同的点的\(dp\)值转移而来,注意如果某一个点已经被强制涂上了某种颜色,那么它的\(dp\)数组的值只有那一种颜色是\(1\),其他的都是\(0\),而对于没有染色的点来说初始值都是\(1\)。
代码
#include <bits/stdc++.h>
using namespace std;
struct node{
int to,next;
}edge[100010 * 2];
int fir[100010],tot;
long long dp[100010][5];
const int mod = 1e9 + 7;
void add(int x,int y){
edge[++tot].to = y;
edge[tot].next = fir[x];
fir[x] = tot;
}
void dfs(int x,int fa){
for(int i = 1;i <= 3;i++){
if(dp[x][i]){
for(int j = 0;j < i;j++)
dp[x][j] = 0;
break;
}
dp[x][i] = 1;
}
for(int i = fir[x];i;i = edge[i].next){
if(edge[i].to == fa)continue;
dfs(edge[i].to,x);
dp[x][1] = (dp[x][1] * (dp[edge[i].to][2] + dp[edge[i].to][3]) % mod) % mod;
dp[x][2] = (dp[x][2] * (dp[edge[i].to][1] + dp[edge[i].to][3]) % mod) % mod;
dp[x][3] = (dp[x][3] * (dp[edge[i].to][1] + dp[edge[i].to][2]) % mod) % mod;
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i = 1;i < n;i++){
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
}
for(int i = 1;i <= m;i++){
int x,y;
cin>>x>>y;
dp[x][y] = 1;
}
dfs(1,0);
cout<<(dp[1][1] + dp[1][2] + dp[1][3]) % mod<<endl;
return 0;
}