Qrafın diametri#1796

Qrafın diametri (Həll təhlili)

Diametri və radiusu hesablamaq üçün bizə bütün təpə cütləri arasındakı ən qısa məsafələr lazımdır. Qrafın təpələrini v_1, v_2, \ldots, v_n ilə, v_i və v_j təpələri arasındakı ən qısa məsafəni isə d(v_i, v_j) ilə işarə edək. Bütün belə məsafələrin matrisini Floyd — Warshall alqoritmi vasitəsilə qururuq.

Floyd — Warshall alqoritmi. Əvvəlcə d(v_i, v_j) v_i və v_j təpələri arasındakı tilin çəkisinə bərabərdir, əgər belə til yoxdursa, sonsuzluğa bərabərdir; d(v_i, v_i) = 0. Sonra v_k təpələrini bir-bir gəzirik və hər (v_i, v_j) təpə cütü üçün yolun v_k təpəsindən keçdikdə qısalıb-qısalmadığını yoxlayırıq:

d(v_i, v_j) = \min(d(v_i, v_j), d(v_i, v_k) + d(v_k, v_j))

v_k təpəsi emal edildikdən sonra matrisdə bütün aralıq təpələri v_1, \ldots, v_k arasında olan ən qısa yolların uzunluqları saxlanılır. Beləliklə, bütün təpə emal edildikdən sonra matrisdə tələb olunan ən qısa məsafələr olacaq.

Eksentrisitetlər. v_i təpəsinin eksentrisiteti r(v_i) ən qısa məsafə matrisinin -ci sətrinin maksimum elementinə bərabərdir:

r(v_i) = \max_{1 \le j \le n} d(v_i, v_j)

Qrafın diametri təpə cütləri arasındakı maksimum məsafədir, yəni r(v_i) eksentrisitetlərinin maksimumudur. Qrafın radiusu isə r(v_i) eksentrisitetlərinin minimumudur.

Misal

Misalda verilən qraf aşağıda göstərilmişdir. Sol şəkildə uzunluğu diametrə bərabər olan ən qısa yol, sağ şəkildə isə eksentrisiteti radiusa bərabər olan təpə qeyd edilmişdir.

Bütün təpə cütləri arasındakı ən qısa məsafələri hesablayaq. Məsələn, və təpələri arasında til yoxdur. 2 \to 4 \to 3 yolunun uzunluğu 5 + 4 = 9-dur, 2 \to 4 \to 1 \to 3 yolu isə daha qısadır: 5 + 2 + 1 = 8, deməli d(v_2, v_3) = 8. Eynilə, d(v_3, v_4) = 3: 3 \to 1 \to 4 yolu uzunluğu 1 + 2 = 3 olmaqla çəkili birbaşa tildən qısadır.

Ən qısa məsafə matrisi və təpələrin eksentrisitetləri aşağıdakı kimidir:

\boldsymbol{r(v_i)}

Maksimum eksentrisitet -ə bərabərdir və və təpələrində əldə edilir — bu qrafın diametridir. Minimum eksentrisitet -ə bərabərdir və təpəsində əldə edilir — bu qrafın radiusudur.

Alqoritmin implementasiyası

Sabitləri və qrafın çəki matrisi -ni elan edək. Olmayan til "sonsuzluq" INF = \mathrm{0x3F3F3F3F} ilə işarə olunur. Bu qiymət mütləq istənilən ən qısa yolun uzunluğundan böyükdür (bu uzunluq 99 \cdot 1000-dən çox ola bilməz). Eyni zamanda, iki sonsuzluğun cəmi hələ də tipinə sığır, buna görə g[i][k] + g[k][j] hesablanarkən overflow baş vermir.

#define MAX 110
#define INF 0x3F3F3F3F
int g[MAX][MAX];

floyd funksiyası Floyd — Warshall alqoritmini implementasiya edir. Xarici dövr aralıq təpəsini gəzir. Hər təpə cütü üçün -dən -yə olan yolun təpəsindən keçməklə qısaldıla bilib-bilmədiyini yoxlayırıq. Əgər g[i][k] + g[k][j] < g[i][j] olarsa, g[i][j] qiymətini yeniləyirik. Ən qısa məsafələr birbaşa matrisində hesablanır.

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];
}

Proqramın əsas hissəsi. təpə sayını və qrafın qonşuluq matrisini oxuyun. qiyməti tilin olmadığını bildirir; onu ilə əvəz edin.

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;
}

Bütün təpə cütləri arasındakı ən qısa məsafələri hesablayın. funksiyası çağırıldıqdan sonra g[i][j] qiyməti və təpələri arasındakı ən qısa məsafəyə bərabərdir.

floyd();

Hər təpəsi üçün onun eksentrisitetini — matrisinin -ci sətrinin maksimum elementini hesablayın. Bütün eksentrisitetlərin maksimumu qrafın diametrinə , minimumu isə radiusuna bərabərdir.

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;
}

Qrafın diametrini və radiusunu çap edin.

printf("%d\n%d\n",diam,radius);

Java implementasiyası

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();
  }
}