Stoer-Vagnerov algoritam

Stoer-Vagnerov algoritam u teoriji grafova predstavlja rekurzivan algoritam koji rešava problem minimalnog reza u neusmerenom težinskom grafu. Predložen je od strane Frenka Vagnera (eng. Frank Wagner) i Methild Stoera (eng. Mechthild Stoer) 1995. godine. Suštinska ideja ovog algoritma je da suzi graf spajajući čvorove najveće težine, sve dok graf ne sadrži samo dva seta kombinovanih najviših čvorova[2]. Nakon svakog suženja, težina spojenog reza se čuva u listi. Konačno rez najmanje težine u listi biće minimum grafa.

Miinalni rez tezinskog grafa minimalne tezine 4.[1]

Rez predstavlja podelu čvorova grafa u dva nesrazmerna podskupa. Minimalan rez je rez čija veličina ili težina nije veća od veličine bilo kog drugog reza. Za težinski graf minimalan rez će jednostavno biti rez sa najmanjim brojem grana. Za težinski graf, zbir svih težina čvorova reza određuje da li je rez minimalan. U praksi, problem mimimalnog reza se uvek raspravlja zajedno sa problemom maksimalnog protoka jer prilikom traženja maksimalnog kapaciteta mreže minimalan rez je "usko grlo" u grafu ili mreži.

Stoer-Vagnerov algoritam minimalnog reza

uredi

Neka je     (   ) težinski neusmeren graf. Neka   budu globalni minimalni rezovi grafa  . Pretpostavimo da  .

Ako   onda su  očigledno   minimalni rez grafa  .[3]

Ovaj algoritam počinje pronalaženjem   minimalnog reza   grafa   dva temena     . Par   ima dve različite mogućnosti,   su minimalni rez grafa   ili pripadaju istoj strani minimalnog reza grafa  . Dakle minimalni rez se može pronaći proveraavanjem grafa   koji nastaje nakon spajanja čvorova   i  . Tokom spajanja, ako su   i   tpovezani granom, ta grana nestaje . Ako su   i   povezani granom sa čvorom najveće težine onda težina čvora dobija novu vrednost   .[3] Algoritam se opisuje sa[2]:

  • FazaMinimalnogReza 
    
   while  
       dodati u   najbliži čvor grafa
       smestiti rez-faze i smanjiti    spajanjem dva čvora koji su dodati poslednji
  • MinimalniRez 
   while  
       FazaMinimalnogReza 
       if rez-faze je lakši od trenutnog minimalnog reza
           then postaviti rez-faze kao trenutni minimalni rez

Algoritam radi u fazama. U fazi FazaMinimalnogReza, podskup   čvorova grafa raste počevši od nekog proizvoljnog čvora dok   ne bude jednako  . U svakom koraku, čvor koji je van skupa  , ali je usko povezan sa skupom  , dodaje se tom skupu. Ovaj postupak se formalno može pokazati kao[2]: dodati čvor najveće težine   tako da   gde je   suma težina svih grana između  . Stoga u samoj fazi par čvorova   i   kao i minimalan   rez   se utvrđuje.[4] Nakon jedne faze FazaMinimalnogReza, dva čvora se spajaju u novi čvor, i grane ta dva čvora se zamenjuju novom granom čija je težina jednaka zbiru prethodne dve grane. A grane koje povezuju ove čvorove se uklanjaju. Ako postoji minimalan rez grafa   odvajanjem   i   onda je   minimalni rez grafa  . Ako nije tako minimalan rez   mora imati   i   na istoj strani. Stoga, algoritam ih spaja u jedan čvor. Pored toga MinimalniRez će se ažurirati nakon svake faze FazaMinimalnogReza. Nakon   faza možemo odrediti minimalni rez.[4]

Primer

uredi

Graf u koraku 1 prikazuje originalni graf   i nasumično bira čvor 2 kao početni čvor za ovaj algoritam. U FazaMinimalnogReza, skup   ima samo čvor 2, najteža ivica je ivica (2,3), tako da se čvor 3 dodaje u skup  . Dalje, skup   sadrži čvor 2 i čvor 3, najteža ivica je (3,4 ), pa se skupu   dodaje čvor 4. Praćenjem ove procedure, poslednja dva čvora su čvor 5 i čvor 1, koji su s i t u ovoj fazi. Njihovim spajanjem, novi graf izgleda kao što je prikazano u koraku 2. U ovoj fazi, težina reza je 5, što je suma ivica (1,2) i (1,5). Sada, je završena prva petlja faze MinimalniRez.

U koraku 2, počevši od čvora 2, najteži ivica je (2,15), pa se čvor 15 stavlja u skup  . Sledeća najteža ivica je (2,3) ili (15,6), biramo (15,6) pa se čvor 6 dodaje u skup. Onda uporedimo ivice (2,3) i (6,7) i izaberemo čvor 3 da bude stavljen u skup  . Poslednja dva čvora su čvor 7 i čvor 8. Dakle, spojimo ivicu (7,8). Minimalan rez je 5, tako da minimum ostaje 5. Sledeći koraci ponavljaju iste operacije na spojeni graf, dok ne ostane samo jedna ivica na grafu, kao što je prikazano u koraku 7. Globalni minimalni rez ima ivicu (2, 3) i ivicu (6,7), što se uočava u koraku 5.

Dokaz korektnosti

uredi

Da bi se dokazala ispravnost ovog algoritma, moramo dokazati da je FazaMinimalnogReza u stvari najmanji   rez grafa, gde su   i   dva čvora koja su poslednja dodata u fazi. Dakle, lema je prikazana ispod:

 Lema 1: FazaMinimalnogReza vraća minimalni  -rez grafa  .

Ovo dokazujemo indukcijom na skupu aktivnih temena. Neka je   proizvoljan   rez, i   rez faze. Moramo pokazati da je  . Primetimo da nam jedno izvršavanje faze FazaMinimalnogReza daje permutaciju svih temena u grafu (gde je   prvi, a   i   su dva temena koja se dodaju poslednja u fazi). Dakle, mi kažemo da je čvor   aktivan ako  , čvor pre čvora   u redosledu temena proizvodenom fazom FazaMinimalnogReza je u   ili obrnuto, što će reći, da su na suprotnim stranama reza. Definišemo   kao skup temena dodat u skup   pre   i   kao rez od skupa   izveden iz  . Za sve aktivne čvorove  :

 

Neka   bude prvi aktivni čvor. Po definiciji sledi da su   and   ekvivalentni.   predstavlja sve čvorove dodate u   pre  , i ivice između tih čvorova i   su ivice koje prelaze rez C. Dakle, kao što je prikazano gore, za aktivne čvorove   i   (  se dodaje u   pre  ):

 

  uvođenjem ,  

    doprinosi   ali ne  

Tako, pošto je   uvek aktivni čvor posto poslednji rez faze odvaja   od   po definiciji, za bilo koji aktivni čvor  :

 

Dakle, maksimalna težina reza faze je jednaka  .

Vremenska složenost

uredi

Vreme izvršavanja algoritma MinimalniRez je jednak vremenu izvršavanja faze FazaMinimalnogReza   puta, koji se poziva na grafove sa smanjenjem broja čvorova i ivica. Za jedno izvršavanje faze FazaMinmalnogReza treba najviše   vremena. Dakle, ukupno trajanje bi trebalo da bude proizvod dve faze kompleksnosti, koji je  [2]. Za dalje poboljšanje, ključ je da se lako odabere sledeći čvor koji se dodaje u skup A, najbliži čvor. Tokom izvržavanja faze, svi čvorovi koji nisu u   nalaze se u prioritetnom redu baziranom na osnovu ključne oblasti. Ključ čvora   je zbir težina ivica koji ga spajaju sa trenutnim A, to jest,  . Kad god se čvor   dodaje u   mora da se izvrši ažuriranje reda.   mora da bude izbrisan iz reda, a ključ svakog čvora   koji se ne nalazi u  , i koji je povezan sa   mora se povećati za težinu ivice  , ako postoji. Pošto se ovo radi upravo jednom za svaku ivicu, ukupno moramo   puta da izvršimo operaciju IzvuciMaksimum i   puta operaciju PovećajKljuč. Korišćenjem Fibonačijevog hipa možemo izvršiti operaciju IzvuciMaksimum u   vremenu i operaciju PovećajKljuč u   vremenu. Tako, vreme potrebno za ovaj ključni korak koji dominira ostatakom faze, je  .[2]

Primer koda[5]

uredi
// Implementacija Stoer-Vagnerovog algoritma preko matrice povezanosti
//
// Vreme izvršavanja:
// O(|V|^3)
//
// ULAZ:
// - graf, konstruisan korišćenjem DodajIvicu()
// IZLAZ:
// - (vrednost minimalnog reza, polovina čvorova u minimalnom rezu)
#include <cmath>
#include <vector>
#include <iostream>

using namespace std;

typedef vector<int> VI;
typedef vector<VI> VVI;

const int INF = 1000000000;

pair<int, VI> NadjiMinimalniRez(VVI &težine) {
  int N = težine.veličina();
  VI koriščen(N), rez, najbolji_rez;
  int najbolja_težina = -1;
  
  for (int faza = N-1; faza >= 0; faza--) {
    VI w = težine[0];
    VI dodati = korišćen;
    int prethodni, poslednji = 0;
    for (int i = 0; i < faza; i++) {
      prethodni = poslednji;
      poslednji = -1;
      for (int j = 1; j < N; j++)
	if (!dodati[j] && (poslednji == -1 || w[j] > w[poslednji])) poslednji = j;
      if (i == faza-1) {
	for (int j = 0; j < N; j++) težine[prethodni][j] += težine[poslednji][j];
	for (int j = 0; j < N; j++) težine[j][prethodni] = težine[prethodnji][j];
	korišćen[poslednji] = true;
	cut.push_back(poslednji);
	if (najbolja_težina == -1 || w[poslednji] < najbolja_težina) {
	 najbolji_rez = rez;
	 najbolja_težina = w[poslednji];
	}
      } else {
	for (int j = 0; j < N; j++)
	 w[j] += težine[poslednji][j];
	dodati[poslednji] = true;
      }
    }
  }
  return napravi_par(najbolja_težina, najbolji_rez);
}


const int maxn = 550;
const int inf = 1000000000;
int n, r;
int ivica[maxn][maxn], dist[maxn];
bool vis[maxn], bin[maxn];
void init()
{
    memset(ivica, 0, sizeof(ivica));  
    memset(bin, false, sizeof(bin));  
}
int contract( int &s, int &t ) // Naći s,t
{
    memset(dist, 0, sizeof(dist));  
    memset(vis, false, sizeof(vis));  
    int i, j, k, min_rez, maxc;  
    for(i = 1; i <= n; i++)  
    {  
        k = -1; maxc = -1;  
        for(j = 1; j <= n; j++)if(!bin[j] && !vis[j] && dist[j] > maxc)  
        {  
            k = j;  maxc = dist[j];  
        }  
        if(k == -1)return min_rez;  
        s = t;  t = k;  
        min_rez = maxc;  
        vis[k] = true;  
        for(j = 1; j <= n; j++)if(!bin[j] && !vis[j])  
            dist[j] += ivica[k][j];  
    }  
    return min_rez;  
}
int Stoer_Vagner()
{
    int min_rez, i, j, s, t, ans;  
    for(min_rez = inf, i = 1; i < n; i++)  
    {  
        ans = contract( s, t );  
        bin[t] = true;  
        if(min_rez > ans)min_rez = ans;  
        if(min_rez == 0)return 0;  
        for(j = 1; j <= n; j++)if(!bin[j])  
            ivica[s][j] = (ivica[j][s] += ivica[j][t]);  
    }  
    return min_rez;  
}

Reference

uredi

Spoljašnje veze

uredi

Minimalni rez (primena u računarskim mrežama)