[笔记][题解]树形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;
} 
原文地址:https://www.cnblogs.com/czy--blog/p/14028106.html