Кількість отриманих очок однозначно визначається першою обраною вершиною. Тому достатньо перебрати всі можливі стартові вершини, обчислити для кожної з них підсумкову кількість очок і вибрати максимальне значення.
Запустимо пошук у глибину з вершини і обчислимо значення weight[v] — розмір піддерева з коренем у вершині (тобто кількість вершин у піддереві ). Нехай to_1, to_2, ..., to_k — сини . Тоді виконується формула:
Другий обхід у глибину виконується по всіх вершинах і дозволяє перерахувати максимальну кількість очок, яку можна отримати, якщо почати гру з даної вершини.
Розглянемо функцію dfs2. Нехай ми знаходимось у вершині , а її батьком є вершина . Якщо першим ходом вибрати вершину , то кількість отриманих очок дорівнює .
Зробимо перехід по ребру (v, to) і покажемо, як обчислити відповідь, якщо почати гру з вершини . Фактично, ми виконуємо переп"ідвішування дерева: корінь переноситься з вершини у вершину .
Зліва зображено дерево з коренем у . Вершина є одним з її нащадків, а — її предком. Справа показано дерево з коренем у .
Щоб обчислити weight[to] для правого дерева, необхідно зі значення у лівому дереві відняти weight[to] лівого дерева і додати кількість вершин в області, позначеній пунктиром. Ця кількість дорівнює n - weight[to].
Приклад
Нехай першою обраною вершиною є . Тоді кількість отриманих очок становитиме .
Якщо першою обраною вершиною буде , то кількість отриманих очок дорівнює . Перехід від вершини до вершини виконаємо наступним чином: віднімемо від s = 25 значення weight[2] = 4 і додамо (9 - weight[4]) = 5. У результаті отримаємо 25 - 4 + 5 = 26, значення для дерева з коренем у вершині .
Максимальна кількість очок дорівнює і досягається, якщо почати гру з вершини .
Вправа
Розглянемо наступне дерево:
Нехай першим ходом обрана вершина . Знайдіть кількість отриманих очок.
Перенесіть корінь з вершини у вершину і обчисліть кількість отриманих очок.
Далі перенесіть корінь з у , з у і з у . Розв'яжіть кожну з отриманих задач.
Реалізація алгоритму
Оголосимо список суміжності графа .
vector\u003cvector\u003cint\u003e\u003e g;
vector\u003cint\u003e weight;Функція dfs1 виконує пошук у глибину з вершини , предком якої є вершина . При цьому обчислюється weight[v] — розмір піддерева з коренем у вершині , тобто кількість вершин у цьому піддереві.
void dfs1(int v, int p)
{
weight[v] = 1;
for (int to : g[v])
if (to != p)
{
dfs1(to, v);
weight[v] += weight[to];
}
}Функція dfs2 виконує пошук у глибину з вершини , предком якої є вершина . Якщо першим ходом гри вибрати вершину , то кількість отриманих очок становитиме .
void dfs2(int v, int p, long long s)
{
res = max(res, s);
for (int to : g[v])
if (to != p) dfs2(to, v, s - weight[to] + n - weight[to]);
}Основна частина програми. Читаємо вхідні дані. Будуємо граф.
scanf("%d", \u0026n);
g.resize(n + 1);
weight.resize(n + 1);
for (i = 1; i \u003c n; i++)
{
scanf("%d %d", \u0026a, \u0026b);
g[a].push_back(b);
g[b].push_back(a);
}Запускаємо пошук у глибину з вершини .
dfs1(1, 0);У змінній обчислюємо суму всіх чисел у масиві weight. Це значення дорівнює кількості отриманих очок у випадку, якщо першою в грі вибрати вершину .
s = 0;
for (i = 1; i \u003c= n; i++)
s += weight[i];Запускаємо другий пошук у глибину з вершини .
dfs2(1, 0, s);Виводимо відповідь.
printf("%lld\n", res);