Bölüm 17: Minimum Kapsayan Ağaçlar

C ile Veri Yapıları ve Algoritmalar · Çalışma Soruları
Kapsayan ağaçlarMinimum maliyetKruskalPrimÖzet
Sercan KÜLCÜ

Çoktan Seçmeli · Kapsayan Ağaçlar

Soru 1: Ağaç Dışı Kenar Eklemek

Bağlantılı bir çizgenin bir kapsayan ağacına ağaç dışı kenarlardan biri ekleniyor. Hangisi doğrudur?

B: Ağaçta her düğüm çifti arasında tek yol vardır; eklenen (u, v) kenarı bu yolla birlikte tek bir döngü kurar. Döngüden herhangi bir kenarı silmek bağlantıyı koparmaz ve n − 1 kenar kalır: yeni bir kapsayan ağaç. Kapsayan ağaçları üretme yöntemi buna dayanır.

Çoktan Seçmeli · Kapsayan Ağaçlar

Soru 2: Her Zaman Doğru Olmayan

n düğümlü bağlantılı bir çizgenin kapsayan ağacı için hangisi her zaman doğru değildir?

D: Yıldız biçimli bir kapsayan ağaçta merkezin derecesi n − 1'dir (K4'ün dört yıldız biçimli kapsayan ağacı gibi). D yalnız yol biçimli ağaçlarda doğrudur. A, B ve C ağacın tanımından gelir: bağlantılı, döngüsüz ve en az kenarlı.

Klasik Soru · Kapsayan Ağaçlar

Soru 3: DFS ve BFS Ağaçları

Komşuluk listeleri küçükten büyüğe sıralı. 0'dan başlayan özyinelemeli DFS ve BFS hangi ağaç kenarlarını seçer? Her birinde kaç kenar ağaç dışında kalır?

012345
Cevabı göster

DFS(0): (0,1), (1,2), (2,3), (3,4), (4,5): her adımda ilk ziyaret edilmemiş komşuya inilir; ağaç bir yoldur.

BFS(0): (0,1), (0,2), (1,3), (1,5), (2,4): önce 0'ın, sonra 1'in ve 2'nin komşuları.

012345012345

solda DFS, sağda BFS ağacı (kalın)

İkisinde de 10 − (6 − 1) = 5 kenar ağaç dışıdır. DFS'de N = {(0,2), (1,3), (1,5), (2,4), (3,5)}, BFS'de N = {(1,2), (2,3), (3,4), (3,5), (4,5)}. Sayı aynı, kenarlar farklı.

Çoktan Seçmeli · Minimum Maliyet

Soru 4: En Ucuz Kenar

Kenar ağırlıkları birbirinden farklı, bağlantılı bir çizgede en ucuz kenar için hangisi kesinlikle doğrudur?

A: Kesit özelliği: kenarın bir ucunu bir yana, diğerini öbür yana koyan bir kesitte bu kenar kesiti geçen en ucuz kenardır; bu yüzden bir MST'de bulunur, ağırlıklar farklı olduğundan MST tektir. Kruskal onu ilk adımda seçer. Prim nereden başlarsa başlasın uçlardan biri ağaca girdiğinde bu kenar adayların en ucuzudur.

Adım Adım Çalıştırma · Kruskal

Soru 5: Kruskal ve ata Dizisi

Şekildeki çizgede Kruskal çalıştırılıyor (birlestir ağırlıklı, kume_bul azaltmasız). Hangi kenarlar seçilir, hangisi reddedilir, sonda ata nedir?

435879261011012345

Kenarlar sıralandı: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11. Her düğüm ayrı küme.

435879261011012345

(3,4) = 2: kökler 3 ve 4 farklı → ağaca. Toplam 2.

435879261011012345

(0,2) = 3: kökler 0 ve 2 farklı → ağaca. Toplam 5.

435879261011012345

(0,1) = 4: kökler 0 ve 1 farklı → ağaca. Toplam 9.

435879261011012345

(1,2) = 5: iki ucun kökü de 0 → döngü, bırakılır.

435879261011012345

(3,5) = 6: kökler 3 ve 5 farklı → ağaca. Toplam 15.

435879261011012345

(2,3) = 7: kökler 0 ve 3 farklı → ağaca. Toplam 22.

435879261011012345

t = n − 1 = 5: döngü biter. (2,4), (1,3), (4,5), (1,5) kenarlarına hiç bakılmadı. MST maliyeti 22.

for (i = 0; i < n; i++) ata[i] = -1;
qsort(k, e, sizeof(kenar), kars);
for (i = 0, t = 0; i < e && t < n - 1; i++) {
    int a = kume_bul(ata, k[i].u);
    int b = kume_bul(ata, k[i].v);
    if (a != b) {                 /* döngü yok */
        T[t++] = k[i];
        birlestir(ata, a, b);
    }                             /* yoksa bırak */
}
if (t < n - 1) printf("agac yok\n");

Çoktan Seçmeli · Kruskal

Soru 6: Yanlış Döngü Denetimi

Kruskal'da döngü denetimi union-find yerine "kenarın iki ucu da daha önce seçilmiş mi?" sorusuyla yapılıyor. Şekildeki çizgede ne olur?

435879261011012345

C: (3,4), (0,2), (0,1) alınır; (1,2)'nin iki ucu seçili olduğundan reddedilir (burada karar doğru). (3,5) alınır. (2,3)'ün iki ucu da seçilmiştir ama farklı öbeklerdedir ({0,1,2} ve {3,4,5}); kenar reddedilir. Sonraki kenarların uçları da hep seçili olduğundan 4 kenarda kalınır. Uçların seçilmiş olması aynı öbekte oldukları anlamına gelmez.

Çıktı Sorusu · Kruskal

Soru 7: Ters Karşılaştırma

Şekildeki çizgede Kruskal döngüsü değiştirilmeden yalnız qsort'a aşağıdaki kars_ters veriliyor. Program ne yazdırır? Bulunan ağaç nedir?

int kars_ters(const void *x, const void *y) {
    const kenar *a = x, *b = y;
    return b->w - a->w;
}
/* ... */
qsort(k, e, sizeof(kenar), kars_ters);
/* Kruskal döngüsü aynı; toplam += k[i].w */
for (j = 0; j < t; j++)
    printf("(%d,%d) ", T[j].u, T[j].v);
printf("= %d\n", toplam);
435879261011012345
Cevabı göster

Çıktı: (1,5) (4,5) (2,4) (1,3) (0,1) = 42

  • Kenarlar büyükten küçüğe denenir: 11, 10, 9, 8 alınır. (2,3) 7, (3,5) 6, (1,2) 5 döngü kurar ve bırakılır; (0,1) 4 alınır, t = 5.
  • Açgözlü seçim yine doğru çalışır ama amaç tersine dönmüştür: bu, en büyük kapsayan ağaçtır (42). Minimum ağaç 22'dir.

Karşılaştırıcının yönü algoritmanın neyi en iyilediğini belirler.

Çoktan Seçmeli · Kruskal

Soru 8: Kruskal'ın Mertebesi

n = 1000 düğüm, e = 3000 kenarlı seyrek bir çizgede Kruskal qsort ve ağırlıklı union-find ile çalıştırılıyor. Toplam zamanın mertebesi nedir?

B: Sıralama O(e log e). Kenar başına iki kume_bul ağırlıklı birleşimle O(log n), toplam O(e log n); e ≤ n² olduğundan log e ≤ 2 log n ve ikisi aynı mertebededir. C listelerde arayan "kötü" kodlamanın, A dizili Prim'in maliyetidir. D için azaltma kuralı da gerekir ve sıralama yine kalır.

Hata Bulma · Kruskal

Soru 9: Kök Yerine Uç

Kruskal döngüsünde tek satır değişmiştir. Şekildeki çizgede program yine 22 bulur. Hata nedir, sonda ata neden yanlıştır, hata hangi durumda sonucu bozar?

for (i = 0, t = 0; i < e && t < n - 1; i++) {
    int a = kume_bul(ata, k[i].u);
    int b = kume_bul(ata, k[i].v);
    if (a != b) {
        T[t++] = k[i];
        birlestir(ata, k[i].u, k[i].v);
    }
}
435879261011012345
Cevabı göster

birlestir'e kökler (a, b) yerine kenarın uçları veriliyor. (2,3) işlenirken a = 0, b = 3 bulunur ama birlestir(ata, 2, 3) çağrılır: ata[2] = 0 ≤ −3 yanlış, 2 kendi kökünden koparılıp 3'ün altına bağlanır.

Sonda ata = [−3, 0, 3, −3, 3, 3]: iki kök kalmıştır ({0,1} ve {2,3,4,5}) ve 0'ın sayacı yanlıştır. Kod 22 bulur, çünkü t = 5 olunca döngü biter. Bir kenar daha işlenseydi (1,3) farklı kökler (0 ve 3) verir ve döngü kurduğu hâlde alınırdı (simülasyonla doğrulandı).

Düzeltme: birlestir(ata, a, b);. Doğru bir sonuç, kodun doğru olduğunu göstermez.

Çoktan Seçmeli · Prim

Soru 10: Prim'de Sıra

Şekildeki çizgede Prim 5 numaralı düğümden başlatılıyor. Düğümler ağaca hangi sırayla katılır?

435879261011012345

A: 5'in adayları (5,3) 6, (5,4) 10, (5,1) 11 → 3. Sonra (3,4) 2 → 4. Adaylar (3,2) 7, (3,1) 8, (4,2) 9, (5,1) 11 → 2. Ardından (2,0) 3 → 0 ve (0,1) 4 → 1. Toplam yine 22'dir: başka başlangıç aynı ağacı başka sırayla kurar. B'de 0'a henüz bağlı bir kenar yoktur.

Adım Adım Çalıştırma · Prim

Soru 11: Dizili Prim

O(n²) Prim 0'dan başlatılıyor. Her turda hangi düğüm seçilir, enaz nasıl değişir? (Düğümlerin yanında enaz değerleri, ✓: ağaçta.)

4358792610110✓14233∞4∞5∞

TV = {0}. enaz[v] = 0'a doğrudan kenarın maliyeti: 1 → 4, 2 → 3; diğerleri ∞.

4358792610110✓142✓37495∞

En küçük enaz: u = 2, kenar (0,2) = 3 ağaca; güncellenen: enaz[3] = 7, enaz[4] = 9.

4358792610110✓1✓2✓3749511

En küçük enaz: u = 1, kenar (0,1) = 4 ağaca; güncellenen: enaz[5] = 11.

4358792610110✓1✓2✓3✓4256

En küçük enaz: u = 3, kenar (2,3) = 7 ağaca; güncellenen: enaz[4] = 2, enaz[5] = 6.

4358792610110✓1✓2✓3✓4✓56

En küçük enaz: u = 4, kenar (3,4) = 2 ağaca; güncelleme yok.

4358792610110✓1✓2✓3✓4✓5✓

En küçük enaz: u = 5, kenar (3,5) = 6 ağaca; güncelleme yok. Toplam 22: Kruskal ile aynı ağaç.

secildi[0] = 1;                    /* TV = {0} */
for (v = 0; v < n; v++)
    enaz[v] = w[0][v], yakin[v] = 0;
for (k = 1; k < n; k++) {
    u = en_yakin(enaz, secildi, n);  /* O(n) */
    if (u < 0) break;                /* agac yok */
    secildi[u] = 1;  toplam += enaz[u];
    for (v = 0; v < n; v++)
        if (!secildi[v] && w[u][v] < enaz[v])
            enaz[v] = w[u][v], yakin[v] = u;
}

Adım Adım Çalıştırma · Prim

Soru 12: Sollin Turları

Sollin (Borůvka) algoritması şekildeki çizgede çalıştırılıyor. Her turda hangi kenarlar seçilir, kaç tur gerekir?

435879261011012345

Her düğüm ayrı bir bileşen.

435879261011012345

Tur 1 seçimleri: 0 → (0,2) 3, 1 → (0,1) 4, 2 → (0,2) 3, 3 → (3,4) 2, 4 → (3,4) 2, 5 → (3,5) 6. Aynı kenarı iki bileşen seçebilir.

435879261011012345

Dört farklı kenar eklenir; (0,2) ve (3,4) ikinci kez geldiğinde uçlar artık aynı kümededir. Bileşenler {0,1,2} ve {3,4,5}.

435879261011012345

Tur 2: iki bileşen de kendisinden çıkan en ucuz kenar olarak (2,3) 7'yi seçer.

435879261011012345

(2,3) eklenir, tek bileşen kaldı. İki turda toplam 22: Kruskal ve Prim ile aynı ağaç. Her turda bileşen sayısı en az yarıya iner.

for (i = 0; i < n; i++) ata[i] = -1;
while (bilesen > 1) {
    for (her bileşen C)
        en[C] = C'den çıkan en ucuz kenar;
    for (her bileşen C)
        if (en[C]'nin uçları farklı kümede) {
            T'ye ekle; birlestir(...);
            bilesen--;
        }
}

Klasik Soru · Prim

Soru 13: MST ile En Kısa Yol

Şekildeki çizgenin MST'sinde (toplam 22) 0'dan 5'e giden yolun uzunluğu nedir? Çizgede 0'dan 5'e en kısa yol kaçtır? 0 kökünden en kısa yol ağacının toplam kenar maliyeti nedir?

435879261011012345
Cevabı göster
  • MST'de 0'dan 5'e tek yol 0 – 2 – 3 – 5: 3 + 7 + 6 = 16.
  • En kısa yol 0 – 1 – 5: 4 + 11 = 15. MST, tek tek uzaklıkları en aza indirmez.
  • En kısa yol ağacı (Dijkstra, kaynak 0): (0,1) 4, (0,2) 3, (2,3) 7, (2,4) 9, (1,5) 11. Uzaklıklar 4, 3, 10, 12, 15. Toplam kenar maliyeti 34 > 22.

MST toplam bağlantı maliyetini, en kısa yol ağacı kökten her düğüme uzaklığı en aza indirir; amaçlar farklıdır.

Çoktan Seçmeli · Prim

Soru 14: Bağlantısız Çizge

İki bileşenli bir çizgede ({0, 1, 2} ve {3, 4}) dizili Prim 0'dan, Kruskal da bütün kenarlarla çalıştırılıyor. Hangisi doğrudur?

D: Prim'de işaretsiz düğümlerin hepsi ∞ olunca en_yakin −1 döner ve döngü kırılır: yalnız 0'ın bileşeni kapsanır. Kruskal kenarları bileşenlerin içinde birleştirir; 2 + 1 = 3 kenar seçer, t < n − 1 olduğu için "agac yok" yazar ama seçtikleri bir minimum kapsayan ormandır.

Çoktan Seçmeli · Özet

Soru 15: Kruskal mı Prim mi?

Kruskal ve Prim için hangisi yanlıştır?

C: Prim yalnız bir ucu ağaçta (TV), diğer ucu dışarıda olan kenarları aday sayar; v ∉ TV koşulu döngüyü zaten engeller. Union-find Kruskal'ın ihtiyacıdır, çünkü onun öbekleri ayrık büyür (A). B: her turda n düğüm taranır. D: farklı ağırlıklarda MST tektir.

Kod Yazma · Özet

Soru 16: Kapsayan Ağaç mı?

n düğümlü bir çizge için t kenarlık T dizisinin bir kapsayan ağaç olup olmadığını union-find ile sınayan int kapsayan_mi(int n, const kenar T[], int t) yordamını yazın (1: evet, 0: hayır, −1: bellek yok). ata dizisi heap'te ayrılsın.

Cevabı göster
int kapsayan_mi(int n, const kenar T[], int t) {
  int *ata = malloc(n * sizeof *ata);
  if (ata == NULL) return -1;
  for (int i = 0; i < n; i++) ata[i] = -1;
  int sonuc = (t == n - 1);         /* kenar sayısı */
  for (int i = 0; sonuc && i < t; i++) {
    int a = kume_bul(ata, T[i].u);
    int b = kume_bul(ata, T[i].v);
    if (a == b) sonuc = 0;            /* döngü */
    else birlestir(ata, a, b);
  }
  free(ata);
  return sonuc;
}

n − 1 kenar ve döngü yok ise ağaç bağlantılıdır. Örnek çizgede Kruskal'ın ağacı 1, (1,2) eklenip (2,3) çıkarılmış küme 0 (0–1–2 döngüsü), dört kenar 0 verir. Her çıkışta free çalışır.

Son

Bölüm 17: Minimum Kapsayan Ağaçlar — Çalışma Soruları
Konu anlatımı: Minimum kapsayan ağaçlar sunumu · Ders notu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.