For each vertex , compute the number of vertices in the subtree where it is the root. If to_1, to_2, ..., to_k are the children of vertex , then
If vertex is a leaf of the tree, then sum[v] = 1.
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 dp[v] = sum[to] - 1 (the removed vertex is not considered saved).
Let vertex have two children to_1 and to_2 (each vertex has a degree of at most ). Then we have two options:
Remove to_1 and recursively save the vertices in the subtree with root to_2. The number of saved vertices will be sum sum[to_1] - 1 + dp[to_2].
Remove to_2 and recursively save the vertices in the subtree with root to_1. The number of saved vertices will be sum[to_2] - 1 + dp[to_1].
Among the two options, choose the one that maximizes the number of saved vertices.
Consider the depth-first search process when examining the edge (v, to).
Let be the second child of vertex . We need to compute the value dp[to] + sum[a] - 1. 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 sum[v] / dp[v]. 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]);