注意到这个问题具有最优子结构性,考虑树上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;
}
标签:SP666,int,题解,else,writeln,Junctions,dp,mod
From: https://www.cnblogs.com/EternalEpic/p/18379141