Розвернути граф#10048

Розвернути граф (Розбір)

Побудуємо 0 - 1 граф, присвоївши наявним ребрам вагу , а їхнім зворотним ребрам — вагу . Потім запустимо пошук в ширину. Довжина найкоротшого шляху з вершини у вершину буде дорівнювати мінімальній кількості ребер, які потрібно обернути.

Приклад

Граф, наведений у прикладі, виглядає наступним чином:

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

Оголосимо константу нескінченність.

#define INF 0x3F3F3F3F

Оголосимо масив найкоротших відстаней та список суміжності графа . Для кожного ребра разом із суміжною вершиною зберігаємо вагу ребра ( або ).

vector\<int\> dist;
vector\<vector\<pair\<int, int\> \> \> g;

Функція bfs реалізує пошук в ширину з вершини .

void bfs(int start)
{
  dist = vector\<int\>(n + 1, INF);
  dist[start] = 0;

  deque\<int\> q;
  q.push_back(start);

  while (!q.empty())
  {
    int v = q.front(); q.pop_front();
    for (auto edge : g[v])
    {
      int to = edge.first;
      int w = edge.second;
      if (dist[to] \> dist[v] + w)
      {
        dist[to] = dist[v] + w;

Залежно від ваги ребра додаємо вершину в кінець або в початок черги.

        if (w == 1)
          q.push_back(to);
        else
          q.push_front(to);
      }
    }
  }
}

Основна частина програми. Читаємо вхідні дані.

scanf("%d %d", &n, &m);
g.resize(n + 1);
for (i = 0; i \< m; i++)
{
  scanf("%d %d", &a, &b);

Орієнтованому ребру a → b присвоюємо вагу , зворотному ребру присвоюємо вагу .

  g[a].push_back({ b, 0 });
  g[b].push_back({ a, 1 });
}

Запускаємо пошук в ширину з вершини .

bfs(1);

Виводимо відповідь — найкоротшу відстань до вершини .

if (dist[n] == INF)
  printf("-1\n");
else
  printf("%d\n", dist[n]);