Разбор
Для каждой вершины вычислим количество вершин в поддереве, где она является корнем. Если — сыновья вершины , то
Если вершина является листом дерева, то .
Пусть равно количеству спасенных вершин в поддереве с корнем , если на данный момент вершина (и только она в поддереве) заражена.
Если вершина имеет только одного сына , то (удаленная вершина не является спасенной).
Пусть вершина имеет двух сыновей и (каждая вершина имеет степень не больше ). Тогда у нас имеется два варианта:
Удалить и рекурсивно спасать вершины поддерева с корнем . Число спасенных вершин составит .
Удалить и рекурсивно спасать вершины поддерева с корнем . Число спасенных вершин составит .
Из двух вариантов следует выбрать тот, при котором количество спасенных вершин будет большим.
Рассмотрим процесс поиска в глубину, когда рассматривается ребро .
Пусть — второй сын вершины . Нам следует вычислить значение . Попробуем его найти, используя только вершины и . Нам известно, что
Откуда
Следовательно
Перебираем сыновей вершины и вычисляем
Пример
В первом примере Хусейн сможет спасти две вершины и , выбрав своим первым ходом вершину номер .
Рассмотрим второй пример. Возле каждой вершины поставим метки . Вершины, выбранные Хусейном, отобразим зеленым цветом.
Например,
Реализация алгоритма
Объявим рабочие массивы.
#define MAX 300005 int sum[MAX], dp[MAX]; vector<vector<int>> g;
Функция dfs совершает поиск в глубину из вершины . Предком вершины является .
void dfs(int v, int p = -1) {
Инициализируем значения и .
sum[v] = 1; dp[v] = 0;
Запускаем поиск в глубину из сыновей вершины .
for (int to : g[v]) if (to != p) { dfs(to, v); sum[v] += sum[to]; }
Вычисляем значение .
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); } }
Основная часть программы. Читаем входные данные.
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); }
Запускаем поиск в глубину из вершины .
dfs(1);
Выводим ответ.
printf("%d\n", dp[1]);