Транспортна Система#9635

Транспортна Система (Розбір)

Давайте запустимо пошук у ширину, починаючи з вихідної вершини та кінцевої вершини . Збережемо найкоротші відстані від в масив і від в масив .

Нехай optDistance позначає найкоротшу відстань між і в оригінальному графі.

Тепер розглянемо можливість побудови нової дороги між вершинами і .

При додаванні дороги до графу створюються нові шляхи:

s → i → j → f~with~length~distS[i] + 1 + distF[j], \\ s → j → i → f~with~length~distS[j] + 1 + distF[i]

Якщо хоча б одна з цих відстаней менша за optDistance, то додавання дороги зменшить найкоротшу відстань між і , і таким чином вона не підходить.

Тепер нам потрібно перевірити всі можливі пари і перевірити, чи зменшить будівництво нової дороги найкоротшу відстань між і .

Приклад

Граф з першого тесту показаний зліва. Найкоротша відстань від вершини до вершини становить . Незалежно від того, яку нову дорогу ми додамо, ця відстань зменшиться. Тому жодна з необхідних доріг не існує.

Граф з другого тесту показаний праворуч. Найкоротша відстань від вершини до вершини становить . Можливі нові дороги позначені жирними лініями. Незалежно від того, яку з цих доріг ми побудуємо, відстань між і не зменшиться.

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

Визначимо константу — максимальну можливу кількість вершин у графі.

#define MAX 1001

Оголосимо матрицю суміжності та масиви для найкоротших відстаней.

int g[MAX][MAX], distS[MAX], distF[MAX];

Функція bfs виконує пошук у ширину від вершини . Вона приймає масив як вхідні дані, де будуть збережені найкоротші відстані.

void bfs(int start, int *dist)
{

Ініціалізуємо масив найкоротших відстаней .

  for (int i = 0; i <= n; i++) dist[i] = -1;
  dist[start] = 0;

Оголосимо чергу і додамо до неї початкову вершину .

  queue<int> q;
  q.push(start);

Поки черга не порожня, беремо вершину з черги.

  while (!q.empty())
  {

    int v = q.front(); q.pop();

Обходимо всі вершини , суміжні з . Якщо вершина ще не відвідана, обчислюємо найкоротшу відстань dist[to] і додаємо її до черги.

    for (int to = 1; to <= n; to++)
      if (g[v][to] && dist[to] == -1)
      {
        q.push(to);
        dist[to] = dist[v] + 1;
      }
  }
}

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

scanf("%d %d %d %d", &n, &m, &s, &f);
memset(g, 0, sizeof(g));

Зчитуємо неорієнтований граф.

for (i = 0; i < m; i++)
{
  scanf("%d %d", &a, &b);
  g[a][b] = g[b][a] = 1;
}

Запускаємо пошук у ширину від вершин та . Найкоротші відстані зберігаються у масивах та відповідно.

bfs(s, distS);
bfs(f, distF);

Нехай optDistance позначає найкоротшу відстань між і в оригінальному графі.

optDistance = distS[f];

Обходимо всі пари вершин та і розглядаємо можливість побудови нової дороги між ними. Змінна відстежує кількість таких допустимих доріг.

res = 0;
for (i = 1; i <= n; i++)
for (j = i + 1; j <= n; j++)

Якщо між вершинами та немає дороги, обчислюємо довжини найкоротших шляхів: s → i → j → f та s → j → i → f. Якщо обидві ці відстані не менші за optDistance, тоді побудова такої дороги дозволена.

  if (g[i][j] == 0)
  {
     if ((distS[i] + distF[j] + 1 >= optDistance) &&
         (distS[j] + distF[i] + 1 >= optDistance))
       res++;
  }

Виводимо відповідь.

printf("%d\n", res);

Реалізація на Java

import java.util.*;

public class Main
{
  static int g[][], distS[], distF[];
  static int n, m, s, f;
  
  static void bfs(int start, int dist[])
  {
    Arrays.fill(dist,-1);
    dist[start] = 0;

    Queue<Integer> q = new LinkedList<Integer>();
    q.add(start);

    while(!q.isEmpty())
    {
      int v = q.poll();
      for (int to = 1; to <= n; to++)
        if (g[v][to] == 1 && dist[to] == -1)
        {
          q.add(to);
          dist[to] = dist[v] + 1;
        }
    }
  }
   
  public static void main(String[] args)
  {
    Scanner con = new Scanner(System.in);
    n = con.nextInt();
    m = con.nextInt();
    s = con.nextInt();
    f = con.nextInt();
    
    g = new int[n+1][n+1];
    distS = new int[n+1];
    distF = new int[n+1];
    
    for (int i = 1; i <= m; i++)
    {
      int a = con.nextInt();
      int b = con.nextInt();
      g[a][b] = g[b][a] = 1;
    }

    bfs(s, distS);
    bfs(f, distF);
    
    int optDistance = distS[f];
    
    int res = 0;
    for(int i = 1; i <= n; i++)
    for (int j = i + 1; j <= n; j++)
      if (g[i][j] == 0)
      {
        if ((distS[i] + distF[j] + 1 >= optDistance) &&
            (distS[j] + distF[i] + 1 >= optDistance))
          res++;
      }

    System.out.println(res);
    con.close();
  }
}