Bakı Metrosu#11865

Bakı Metrosu (Həll təhlili)

Metro sxemi təpədən və tilindən ibarət əlaqəli istiqamətləndirilməmiş qrafdır. təpəsi olan və məhz n - 1 tilə malik əlaqəli qraf ağacdır. Ağaca daha bir til əlavə etmək məhz bir dövr yaradır. Buna görə də şərtdəki qraf yeganə dövrdən (halqavari xətdən) ibarətdir ki, onun təpələrindən ağaclar (bəlkə də boş) asılmışdır.

Hər bir təpə üçün dövrün ən yaxın təpəsinə qədər olan ən qısa yolun uzunluğunu tapmaq lazımdır. Dövr təpələri üçün cavab -a bərabərdir. Məsələ iki mərhələdə həll olunur.

1-ci mərhələ. Dövrün ayrılması: yarpaqların ardıcıl silinməsi

Bütün təpələrin dərəcələrini hesablayaq. Dərəcəsi olan bütün təpələri, yəni yarpaqları, növbəyə yerləşdirək. Növbə boş olmayana qədər, ondan təpəsini çıxarırıq və onu silinmiş kimi qeyd edirik. Sonra onun hələ silinməmiş hər bir qonşusunun dərəcəsini azaldırıq. Əgər qonşunun dərəcəsi -ə bərabər olarsa, deməli o özü yarpağa çevrilib və biz onu növbəyə əlavə edirik.

Proses tamamlandıqdan sonra yalnız dövrün təpələri silinməmiş qalacaq. Bu, iki müşahidədən irəli gəlir:

2-ci mərhələ. Çoxmənbəli enlik üzrə axtarış

Bütün dövr təpələri üçün d[v] = 0 qəbul edək, qalanları üçün isə d[v] = –1 (ziyarət edilməyib). Bütün dövr təpələrini eyni zamanda növbəyə yerləşdirək və onlardan enlik üzrə axtarışı başladaq. təpəsi növbədən çıxarıldıqda, onun hər bir ziyarət edilməmiş qonşusu d[w] = d[u] + 1 qiymətini alır və növbəyə əlavə olunur.

Çoxmənbəli enlik üzrə axtarış təpələri həmin çoxluğa qədər olan məsafənin qeyri-azalan sırası ilə emal edir. Buna görə də -dən halqavari xəttə qədər minimal keçid sayına bərabərdir. Dövrdən kənarda olan hər şey ağac olduğu üçün, hər stansiyadan halqaya qədər olan yol əslində yeganədir.

Bu proses tərs topoloji sıralamanı xatırladır: biz yalnız "daxili" təpələr qalana qədər yarpaqları ardıcıl olaraq siririk — məhz onlar da dövrü təşkil edir.

Bundan sonra dövrə daxil olan bütün təpələrdən eyni zamanda enlik üzrə axtarışı işə salırıq. Beləliklə, qalan hər bir təpə üçün halqanın ən yaxın təpəsinə qədər minimal addım (keçid) sayı müəyyən edilir.

Misal

Birinci misalda bütün təpələr bir dövrə daxildir, buna görə də hər biri üçün məsafə -a bərabərdir.

İkinci misalda dövrü və təpələri yaradır, qalan təpələr isə ondan müəyyən məsafədədir.

Alqoritmin reallaşdırılması

Qrafın qonşuluq siyahısını , həmçinin köməkçi massivləri elan edək:

növbəsi alqoritmin hər iki mərhələsində istifadə olunur: əvvəlcə yarpaqların ardıcıl silinməsi üçün, sonra isə çoxmənbəli enlik üzrə axtarış üçün.

vector\u003cvector\u003cint\u003e \u003e g;
vector\u003cint\u003e used, dist, deg;
queue\u003cint\u003e q;

Giriş məlumatlarını oxuyuruq. Qrafı qururuq.

scanf("%d", \u0026n);
g.resize(n + 1);
for (i = 0; i \u003c n; i++)
{
  scanf("%d %d", \u0026a, \u0026b);
  g[a].push_back(b);
  g[b].push_back(a);
}

Təpələrin ilkin dərəcələrini hesablayırıq: təpəsinin dərəcəsi onun qonşuluq siyahısının ölçüsünə bərabərdir. Bütün yarpaqları, yəni dərəcəsi olan təpələri, növbəsinə yerləşdiririk və dərhal silinmiş kimi qeyd edirik (used[i] = 1).

used.resize(n + 1, 0);
deg.resize(n + 1, 0);
for (i = 1; i \u003c= n; i++)
{
  deg[i] = g[i].size();
  if (deg[i] == 1)
  {
    q.push(i);
    used[i] = 1;
  }
}

Yarpaqları ardıcıl olaraq siririk. Zahirən bu dövr enlik üzrə axtarışa oxşayır, lakin təpə ilk dəfə aşkarlananda deyil, yalnız özü yarpağa çevriləndə növbəyə düşür. Növbədən təpəsini çıxarırıq və onun qonşularını araşdırırıq. Artıq silinmiş kimi qeyd edilmiş qonşuları buraxırıq. Hər bir silinməmiş qonşu üçün dərəcəni azaldırıq, çünki (v, to) tili təpəsi ilə birlikdə qrafdan yox olur.

while (!q.empty())
{
  int v = q.front(); q.pop();
  for (int to : g[v])
    if (used[to] == 0)
    {
      deg[to]--;

Əgər azaldıqdan sonra to təpəsinin dərəcəsi -ə bərabər olarsa, deməli onun yalnız bir silinməmiş qonşusu qalıb, yəni o özü yarpağa çevrilib. Onu növbəyə yerləşdiririk və silinmiş kimi qeyd edirik. Dövr təpələri heç vaxt dərəcəsinə çatmır, buna görə də proses halqavari xətdə dayanır.

      if (deg[to] == 1)
      {
        q.push(to);
        used[to] = 1;
      }
    }
}

Bu anda used[i] = 0 bərabərliyi yalnız o halda doğrudur ki, təpəsi dövrə aiddir.

massivini qiyməti ilə ilkinləşdiririk (bütün təpələr ziyarət edilməyib). Növbə bu anda artıq boşdur, lakin boş növbənin təyin edilməsi ikinci dolanmadan əvvəl onu açıq şəkildə sıfırlayır. Sonra dövrün hər bir təpəsini növbəyə yerləşdiririk və onun üçün dist[i] = 0 qəbul edirik — halqavari xəttin bütün təpələri eyni zamanda enlik üzrə axtarışın mənbələrinə çevrilir.

dist = vector\u003cint\u003e(n + 1, -1);
q = queue\u003cint\u003e();
for (i = 1; i \u003c= n; i++)

  if (used[i] == 0)
  {
    q.push(i);
    dist[i] = 0;
  }

Çoxmənbəli enlik üzrə axtarışı işə salırıq. Növbədən təpəsini çıxarırıq. Onun hər bir ziyarət edilməmiş to~(dist[to] = –1) qonşusu dist[v] + 1 məsafəsini alır və növbəyə əlavə olunur. Dövr təpələri əvvəldən məsafəsi ilə qeyd edilib, buna görə dolanma halqaya qayıtmır və yalnız asılı ağacların dərinliyinə doğru yayılır. Təpələr növbədən məsafənin qeyri-azalan sırası ilə çıxarıldığı üçün, hər bir dist[to] qiyməti ən qısadır.

while (!q.empty())
{
  int v = q.front(); q.pop();
  for (int to : g[v])
    if (dist[to] == -1)
    {
      q.push(to);
      dist[to] = dist[v] + 1;
    }
  }

Stansiyalardan halqavari xəttə qədər olan məsafələri onların nömrələri sırası ilə çap edirik.

for (i = 1; i \u003c= n; i++)
   printf("%d ", dist[i]);
printf("\n");