Розбір
For each vertex , compute the number of vertices in the subtree where it is the root. If are the children of vertex , then
If vertex is a leaf of the tree, then .
Let be the number of saved vertices in the subtree with root , assuming that currently vertex (and only it in the subtree) is infected.
If vertex has only one child , then (the removed vertex is not considered saved).
Let vertex have two children and (each vertex has a degree of at most ). Then we have two options:
Remove and recursively save the vertices in the subtree with root . The number of saved vertices will be sum .
Remove and recursively save the vertices in the subtree with root . The number of saved vertices will be .
Among the two options, choose the one that maximizes the number of saved vertices.
Consider the depth-first search process when examining the edge .
Let be the second child of vertex . We need to compute the value . Let's try to find it using only the vertices and . We know that:
From which it follows that:
Thus,
Iterate over the children of the vertex and compute:
Example
In the first example, Huseyn is able to save two vertices, and , by choosing vertex number as his first move.|
Consider the second example. Next to each vertex , place the labels . The vertices chosen by Huseyn are displayed in green.
For example,
Algorithm implementation
Declare the arrays.
#define MAX 300005 int sum[MAX], dp[MAX]; vector<vector<int>> g;
The function dfs performs a depth-first search starting from vertex . The parent of vertex is .
void dfs(int v, int p = -1) {
Initialize the variables and .
sum[v] = 1; dp[v] = 0;
Perform a depth-first search starting from the children of vertex .
for (int to : g[v]) if (to != p) { dfs(to, v); sum[v] += sum[to]; }
Compute the value of .
for (int to : g[v]) if (to != p) { dp[v] = max(dp[v], sum[to] - 1); // if 1 son dp[v] = max(dp[v], dp[to] + sum[v] - sum[to] - 2); } }
The main part of the program. Read the input data.
scanf("%d", &n); g.clear(); g.resize(n + 1); memset(dp, 0, sizeof(dp)); memset(sum, 0, sizeof(sum)); for (i = 1; i < n; i++) { scanf("%d %d", &u, &v); g[u].push_back(v); g[v].push_back(u); }
Perform a depth-first search starting from vertex .
dfs(1);
Print the answer.
printf("%d\n", dp[1]);