SP666 VOCV - Con-Junctions 题解

注意到这个问题具有最优子结构性,考虑树上dp。记 \(dp[i][0/1]\) 表示 i 号节点不放灯或放灯的最小值,\(s[i][0/1]\) 为对应的方案数。

那么我们可以进行如下转移: \(dp[u][0] = \sum_{u->v} dp[v][1]\) \(dp[u][1] = \sum_{u->v} \min(dp[v][0], dp[v][1])\)

在更新对应的dp数组时,我们用乘法原理同步更新s数组即可。

const int N = 100015, mod = 10007;
int T, n; vector <int> G[N];

int dp[N][2], s[N][2];
inline void dfs(int u, int f) {
	dp[u][1] = 1;
	for (auto v : G[u]) {
		if (v == f) continue;
		dfs(v, u);
		if (dp[v][1] > dp[v][0]) dp[u][1] += dp[v][0], s[u][1] = s[u][1] * s[v][0] % mod;
		else if (dp[v][1] < dp[v][0]) dp[u][1] += dp[v][1], s[u][1] = s[u][1] * s[v][1] % mod;
		else dp[u][1] += dp[v][0], s[u][1] = s[u][1] * (s[v][0] + s[v][1]) % mod;
		dp[u][0] += dp[v][1]; s[u][0] = s[u][0] * s[v][1] % mod;
	}
}

signed main(void) {
	for (read(T); T; T--) {
		read(n);
		for (int i = 1; i <= n; i++) G[i].clear(), dp[i][0] = dp[i][1] = 0, s[i][0] = s[i][1] = 1;
		for (int i = 1, u, v; i < n; i++) read(u), read(v), G[u].push_back(v), G[v].push_back(u);
		dfs(1, 0);
		if (dp[1][1] > dp[1][0]) writeln(dp[1][0], ' '), writeln(s[1][0]);
		else if (dp[1][1] < dp[1][0]) writeln(dp[1][1], ' '), writeln(s[1][1]);
		else writeln(dp[1][0], ' '), writeln((s[1][0] + s[1][1]) % mod);
	}
    return 0;
}
posted @ 2024-08-25 16:59  EternalEpic  阅读(70)  评论(0)    收藏  举报