Довгий шлях#11452

Довгий шлях (Розбір)

Знайдемо топологічне сортування графа. Позначимо через максимальну кількість міст, яке можна відвідати по шляху, починаючи з вершини .

Розглянемо вершини в порядку топологічного сортування. Нехай — поточна вершина. Позначимо через v_1, v_2, ..., v_k вершини, до яких ведуть ребра з . Тоді оновимо значення:

dp[u] = max(dp[v_i] + 1), 1 \le i \le k

Спочатку встановимо dp[u] = 0~(1 \le u \le n).

Після обробки всіх вершин знаходимо найбільше значення в масиві . Воно дорівнює довжині максимального шляху в графі.

Приклад

Ліворуч наведено граф із першого прикладу. Праворуч — із другого. Найдовші шляхи виділені.

У першому прикладі найдовший шлях дорівнює dp_1 = 3.

У другому прикладі найдовший шлях дорівнює dp_4 = 2.

Реалізація алгоритму

Оголосимо список суміжності графа .

vector<vector<int> > g;

Функція dfs виконує пошук у глибину, починаючи з вершини . Сортуємо вершини графа топологічно і записуємо їх в масив .

void dfs(int v)
{
  used[v] = 1;
  for (int to : g[v])
    if (used[to] == 0) dfs(to);
  top.push_back(v);
}

Основна частина програми. Читаємо вхідні дані. Будуємо список суміжності орієнтованого графа.

scanf("%d %d", &n, &m);
g.resize(n + 1);
while (m--)
{
  scanf("%d %d", &a, &b);
  g[a].push_back(b);
}

Запускаємо пошук у глибину на несв'язаному графі.

used.resize(n + 1);
for (i = 1; i <= n; i++)
  if (used[i] == 0) dfs(i);

Перебираємо вершини графа в порядку, зворотному до їх топологічного сортування, тобто перебираємо вершини масиву зліва направо.

dp.resize(n + 1);
for (int u : top)
{

Шлях з вершини в саму себе має довжину (ініціалізація).

  dp[u] = 0;

Перебираємо вершини , суміжні з . Розглядаємо ребро .

  for (int v : g[u])

Для всіх таких вершин шукаємо максимум серед значень dp[v] + 1.

    dp[u] = max(dp[u], dp[v] + 1);
}

Знаходимо і виводимо найбільший елемент у масиві . Він відповідає довжині найдовшого шляху в графі.

res = *max_element(dp.begin(), dp.end());
printf("%d\n", res);