Щоб обчислити діаметр і радіус, нам потрібні найкоротші відстані між усіма парами вершин. Позначимо через v_1, v_2, \ldots, v_n вершини графа, а через d(v_i, v_j) — найкоротшу відстань між вершинами v_i та v_j. Побудуємо матрицю всіх таких відстаней за допомогою алгоритму Флойда — Воршелла.
Алгоритм Флойда — Воршелла. Спочатку d(v_i, v_j) дорівнює вазі ребра між вершинами v_i та v_j, або нескінченності, якщо такого ребра немає; d(v_i, v_i) = 0. Потім ми по черзі перебираємо вершини v_k і для кожної пари вершин (v_i, v_j) перевіряємо, чи стане шлях коротшим, якщо він проходитиме через вершину v_k:
Після обробки вершини v_k матриця містить довжини найкоротших шляхів, усі проміжні вершини яких лежать серед v_1, \ldots, v_k. Отже, після обробки всіх вершин матриця міститиме потрібні найкоротші відстані.
Ексцентриситети. Ексцентриситет r(v_i) вершини v_i дорівнює максимальному елементу -го рядка матриці найкоротших відстаней:
Діаметр графа — це максимальна відстань між парою вершин, тобто максимум серед ексцентриситетів r(v_i). Радіус графа — це мінімум серед ексцентриситетів r(v_i).
Приклад
Граф, наведений у прикладі, показано нижче. На лівому рисунку виділено найкоротший шлях, довжина якого дорівнює діаметру, а на правому — вершину, ексцентриситет якої дорівнює радіусу.
Обчислимо найкоротші відстані між усіма парами вершин. Наприклад, між вершинами і немає ребра. Шлях 2 \to 4 \to 3 має довжину 5 + 4 = 9, тоді як шлях 2 \to 4 \to 1 \to 3 є коротшим: 5 + 2 + 1 = 8, тому d(v_2, v_3) = 8. Аналогічно, d(v_3, v_4) = 3: шлях 3 \to 1 \to 4 довжиною 1 + 2 = 3 коротший за пряме ребро вагою .
Матриця найкоротших відстаней та ексцентриситети вершин мають такий вигляд:
\boldsymbol{r(v_i)} | |||||
Максимальний ексцентриситет дорівнює і досягається у вершинах та — це діаметр графа. Мінімальний ексцентриситет дорівнює і досягається у вершині — це радіус графа.
Реалізація алгоритму
Оголосимо константи та матрицю ваг графа . Відсутнє ребро позначається «нескінченністю» INF = \mathrm{0x3F3F3F3F}. Це значення гарантовано більше за довжину будь-якого найкоротшого шляху (яка не перевищує 99 \cdot 1000). Водночас сума двох нескінченностей все ще вміщується в тип , тому при обчисленні g[i][k] + g[k][j] переповнення не відбувається.
#define MAX 110
#define INF 0x3F3F3F3F
int g[MAX][MAX];Функція floyd реалізує алгоритм Флойда — Воршелла. Зовнішній цикл перебирає проміжну вершину . Для кожної пари вершин ми перевіряємо, чи можна скоротити шлях з до , проходячи через вершину . Якщо g[i][k] + g[k][j] < g[i][j], ми оновлюємо значення g[i][j]. Найкоротші відстані обчислюються безпосередньо в матриці .
void floyd(void)
{
int i, j, k;
for(k = 0; k < n; k++)
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
if (g[i][k] + g[k][j] < g[i][j])
g[i][j] = g[i][k] + g[k][j];
}Основна частина програми. Прочитаємо кількість вершин та матрицю суміжності графа. Значення означає, що ребра немає; замінимо його на .
scanf("%d",&n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
{
scanf("%d",&g[i][j]);
if (g[i][j] < 0) g[i][j] = INF;
}Обчислимо найкоротші відстані між усіма парами вершин. Після виклику значення g[i][j] дорівнюватиме найкоротшій відстані між вершинами та .
floyd();Для кожної вершини обчислимо її ексцентриситет — максимальний елемент -го рядка матриці . Максимум серед усіх ексцентриситетів дорівнює діаметру графа , а мінімум — радіусу графа .
diam = 0; radius = INF;
for(i = 0; i < n; i++)
{
max = 0;
for(j = 0; j < n; j++)
if (g[i][j] > max) max = g[i][j];
if (max > diam) diam = max;
if (max < radius) radius = max;
}Виведемо діаметр і радіус графа.
printf("%d\n%d\n",diam,radius);Реалізація на Java
import java.util.Scanner;
public class Main
{
static final int INF = 0x3F3F3F3F;
static int g[][];
static int n;
static void floyd()
{
for(int k = 0; k < n; k++)
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
if (g[i][k] + g[k][j] < g[i][j])
g[i][j] = g[i][k] + g[k][j];
}
public static void main(String[] args)
{
Scanner con = new Scanner(System.in);
n = con.nextInt();
g = new int[n][n];
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
g[i][j] = con.nextInt();
if (g[i][j] < 0) g[i][j] = INF;
}
floyd();
int diam = 0, radius = INF;
for(int i = 0; i < n; i++)
{
int max = 0;
for(int j = 0; j < n; j++)
if (g[i][j] > max) max = g[i][j];
if (max > diam) diam = max;
if (max < radius) radius = max;
}
System.out.println(diam + "\n" + radius);
con.close();
}
}