За допомогою двох запусків пошуку в глибину знайдемо діаметр дерева.
Оскільки дерево — це зв’язний граф без циклів, як пошук в глибину (DFS), так і пошук в ширину (BFS) коректно знаходять найкоротші відстані від стартової вершини до всіх інших.
Позначимо через і дві вершини, що знаходяться на максимальній відстані одна від одної — тобто утворюють діаметр дерева.
Визначимо найкоротші відстані від вершини до всіх інших і збережемо їх в масиві , а від вершини — у масиві .
Тоді для кожної вершини i найбільша відстань до іншої вершини буде дорівнювати
Приклад
Розгляньмо дерево з прикладу.
Діаметром дерева може бути, наприклад, шлях між вершинами і .
Реалізація алгоритму
Вхідне дерево зберігається у вигляді списку суміжності .
Найкоротші відстані від вершин та зберігаються в масивах і .
vector<vector<int>> g;
vector<int> dista, distb;Функція dfs виконує пошук в глибину з вершини .
Параметр позначає найкоротшу відстань від джерела до вершини .
Результати зберігаються в масиві .
Параметр вказує на предка вершини в процесі обходу.
void dfs(int v, int d, vector<int>& dist, int p = -1)
{Записуємо в dist[v] найкоротшу відстань від джерела до вершини .
dist[v] = d;Перебираємо всі ребра (v, to). Для кожного сина вершини (вершина не є предком вершини ) запускаємо пошук в глибину.
for (int to : g[v])
if (to != p) dfs(to, d + 1, dist, v);
}Основна частина програми. Читаємо вхідні дані.
scanf("%d", &n);
g.resize(n + 1);
dista.resize(n + 1);
distb.resize(n + 1);Будуємо неорієнтоване дерево.
for (i = 1; i < n; i++)
{
scanf("%d %d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}Знаходимо найкоротші відстані від вершини . Найвіддаленішою від неї вершиною є вершина .
dfs(1, 0, dista, -1);
a = max_element(dista.begin() + 1, dista.begin() + n + 1) - dista.begin();Потім обчислюємо найкоротші відстані від вершини і зберігаємо їх в масиві . Найвіддаленішою вершиною від виявляється вершина . Відстань між вершинами і є діаметром дерева.
dfs(a, 0, dista, -1);
b = max_element(dista.begin() + 1, dista.begin() + n + 1) - dista.begin();Обчислюємо найкоротші відстані від вершини і зберігаємо їх в масиві .
dfs(b, 0, distb, -1);Для кожної вершини виводимо відстань до найвіддаленішої від неї вершини.
for (i = 1; i <= n; i++)
printf("%d ", max(dista[i], distb[i]));
printf("\n");Python реалізація
Збільшимо стек для рекурсії.
import sys
sys.setrecursionlimit(1000000)Функція dfs виконує пошук в глибину з вершини .
Параметр позначає найкоротшу відстань від джерела до вершини .
Результати зберігаються в масиві .
Параметр вказує на предка вершини в процесі обходу.
def dfs(v, d, dist, p =- 1):Записуємо в dist[v] найкоротшу відстань від джерела до вершини .
dist[v] = dПеребираємо всі ребра (v, to). Для кожного сина вершини (вершина не є предком вершини ) запускаємо пошук в глибину.
for to in g[v]:
if to != p:
dfs(to, d + 1, dist, v)Основна частина програми. Читаємо вхідні дані.
n = int(input())
g = [[] for _ in range(n + 1)]
dista = [0] * (n + 1)
distb = [0] * (n + 1)Будуємо неорієнтоване дерево.
for _ in range(n - 1):
u, v = map(int, input().split())
g[u].append(v)
g[v].append(u)Знаходимо найкоротші відстані від вершини . Найвіддаленішою від неї вершиною є вершина .
dfs(1, 0, dista)
a = dista.index(max(dista[1:]))Потім обчислюємо найкоротші відстані від вершини і зберігаємо їх в масиві . Найвіддаленішою вершиною від виявляється вершина . Відстань між вершинами і є діаметром дерева.
dfs(a, 0, dista)
b = dista.index(max(dista[1:]))Обчислюємо найкоротші відстані від вершини і зберігаємо їх в масиві .
dfs(b, 0, distb)Для кожної вершини виводимо відстань до найвіддаленішої від неї вершини.
result = [max(dista[i], distb[i]) for i in range(1, n + 1)]
print(*result)