树上DP

题目链接:
https://ac.nowcoder.com/acm/contest/11187/D

题意:
给出一棵 n 个点的树,有 x 种普通颜色,y 种特殊颜色现在要给树上的每个节点染色,
普通颜色染色没有限制,但两个相邻的节点不能染相同颜色的特殊颜色,求染色方案数,答案对 998244353 取模。

解答:
树上DP。从根节点遍历到叶子节点,dp[u][1/0] 来保存以u为根,填上普通颜色(或者特殊颜色)的方案数。

#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int N = 1e6+5;
const int mod = 998244353;
int dp[N][2], x, y;
vector<int> vis[N];
 
inline int read() { // 内联函数  调用时直接将整个代码复制过去,减少了调用函数的时间 
	int f = 1, k = 0;
	char c = getchar();
	while (c<'0' || c>'9') {if (c=='-') f = -1; c = getchar();}
	while (c>='0' && c<='9') {k = k*10+c-'0'; c = getchar();}
	return f*k;
}

void dfs(int u, int fa) { // 由根节点 逐步 往下遍历 
    dp[u][0] = 1, dp[u][1] = 1; // 以u为根 且u填了一个普通颜色(特殊颜色)时,子树的染色方案数   均初始化为 1 
	for (int i=0; i<vis[u].size(); i++) {
		if (vis[u][i] == fa) continue; // 若 子节点 等于 其父节点 则 continue 
		dfs(vis[u][i], u); // 继续往下遍历
		dp[u][0] = dp[u][0]*(dp[vis[u][i]][0]*x%mod+dp[vis[u][i]][1]*y%mod)%mod; // 该节点 * 子节点可能的颜色
		dp[u][1] = dp[u][1]*(dp[vis[u][i]][0]*x%mod+dp[vis[u][i]][1]*(y-1)%mod)%mod; // 因为特殊颜色不能相邻 故其子节点特殊颜色种数 y-1  
	}
	return ;
}

signed main() { // signed = signed int = int
	int n, u, v;
	while (cin >> n >> x >> y) {
		for (int i=1; i<=n-1; i++) {
			u = read(), v = read();
			vis[u].push_back(v); // 利用 vector数组 来建树 
			vis[v].push_back(u);
		}
		dfs(1, 0);
		cout << (dp[1][0]*x%mod+dp[1][1]*y%mod)%mod << endl; // 根节点 分别乘上 x 种普通颜色和 y 种特殊颜色,即得到总的方案数
	}
	return 0;
}
posted @ 2022-03-23 16:31  jianping5  阅读(48)  评论(0)    收藏  举报