[笔记][题解]树形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;
} 
posted @ 2020-11-24 00:07  czyczy  阅读(36)  评论(0编辑  收藏  举报