Давайте запустимо пошук у ширину, починаючи з вихідної вершини та кінцевої вершини . Збережемо найкоротші відстані від в масив і від в масив .
Нехай optDistance позначає найкоротшу відстань між і в оригінальному графі.
Тепер розглянемо можливість побудови нової дороги між вершинами і .
При додаванні дороги до графу створюються нові шляхи:
Якщо хоча б одна з цих відстаней менша за 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();
}
}