Јенов алогритам

Извор: testwiki
Пређи на навигацију Пређи на претрагу

Јенов алгоритам рачуна К-најкраћих путања без циклова у графу са једним извором и не-негативним ценама грана.[1] Алгоритам је објављен 1971. од стране Ђин Ј. Јена и користи било који алгоритам за тражење најкраћег пута у графу да пронађе најбољу путању, а затим наставља да пронађе К-1 одступања од најбоље путање.[2]

Алгоритам

Терминологија и ознаке

Ознака Опис
N Величина графа, тј. број чворова у графу.
(i) i-ти чвор графа, где i узима вредности од 1 до N. Ово значи да је чвор (1) извор, а чвор (N) понор графа.
dij Цена гране између (i) и (j), под претпоставком да (i)(j) и dij0.
Ak k-та најкраћа путања од (1) до (N), где k иде од 1 до K. Тада је Ak=(1)(2k)(3k)(Qkk)(N), а (2k) је други чвор k-те најкраће путање, (3k) је трећи чвор k-те најкраће путање, итд.
Aki Одступајућа путања од Ak1 код чвора (i), где i иде од 1 до Qk. Максимална вредност i је Qk, који је чвор одмах испред понора у k најкраћој путањи. Ово значи да одступајућа путања не може да одступа од k1 најкраће путање у понору. Путање Ak и Ak1 прате исти пут до i-тог чвора, где је (i)k(i+1)k грана не припада ни једној путањи у Aj, и j узима вредности од 1 до k1.
Rki Коренска путања од Aki која прати Ak1 све до i-тог чвора од Ak1.
Ski Споредна путања од Aki која почиње у i-том чвору и завршава се у понору.

Опис

Алгоритам се може поделити на два дела, одређивање прве к-најкраће путање, A1, а затим, одређивање свих осталих к-најкраћих путања. Да бисмо одредили A1, најкраћу путању од извора до понора, можемо искористити било који ефикасни алгоритам за тражење најкраћег пута у графу.

Да бисмо пронашли Ak, где k узима вредности од 2 до K, алгоритам претпоставља да су све путање од A1 до Ak1 претходно пронађене. k-то понављање може бити подељено на два поступка, проналажење свих одступања Aki и одабир најкраћег који ће постати Ak. Обратите пажњу да у овом понављању i узима вредности од 1 до Qkk.

Први поступак се може додатно поделити на три операције: проналажење Rki, проналажење Ski, а затим додавање Aki у спремиште B. Коренска путања, Rki, се одабира тражењем потпутање у Ak1 која прати првих i чворова од Aj, где j узима вредности од 1 до k1. Онда, ако је путања пронађена, цена гране di(i+1) од Aj се поставља на бесконачно. Следеће, споредна путања, Ski, се проналази тако што се рачуна најкраћа путања од споредног чвора i до понора. Одстрањивање претходно кориштених грана од (i) до (i+1) осигурава нам да је споредна путања различита. Aki=Rki+Ski, збир коренске путање и споредне путање, се додаје у B. Следеће, гране које су уклоњене, тј. чија цена је била постављен на бесконачно, се враћају у првобитно стање.

Други поступак одређује одговарајућу путању за Ak, тако што проналази путању у спремишту B са најмањом ценом. Ова путања се уклања из B и убацује у A и алгоритам наставља са следећим кораком. Ако је број путањи у B једнак или већи од броја к-најкраћих путања које још треба пронаћи, онда се тражене путање из B додају у A и алгоритам се завршава.

Псеудокод

Алгоритам претпоставља да се користи Дијкстра алгоритам за тражење најкраћих путања између два чвора, али се може искористити и неки други алгоритам.

function YenKSP(Graph, source, sink, K):
   // Одређивање најкраће путање од извора до понора
   A[0] = Dijkstra(Graph, source, sink);
   // Иницијализујемо хип у коме чувамо потенцијалну к-ту најкраћу путању
   B = [];
   
   for k from 1 to K:
       // Споредни чвор је из опсега од првог од претпоследњег у најкраћој путањи
       for i from 0 to size(A[k − 1]) − 1:
           
           // Споредни чвор се узима преходне к-најкраће путање, k − 1.
           spurNode = A[k-1].node(i);
           // Низ чворова од извора до споредног чвора претходне к-најкраће путање
           rootPath = A[k-1].nodes(0, i);
           
           for each path p in A:
               if rootPath == p.nodes(0, i):
                   // Уклонити везе које су део претходне најкраће путање које деле исту коренску путању
                   remove p.edge(i, i + 1) from Graph;
           
           // Израчунати споредну путању од споредног чвора до понора
           spurPath = Dijkstra(Graph, spurNode, sink);
           
           // Цела путања настаје спајање коренске путање и споредне путање
           totalPath = rootPath + spurPath;
           // Додати потензијалну к-најкраћу путању на хип
           B.append(totalPath);
           
           // Вратити гране које су уклоњене из графа
           restore edges to Graph;
       
       // Сортирати потенцијалне к-најкраће путање по цени.
       B.sort();
       // Путања најмање цене постаје к-та најкраћа путања
       A[k] = B[0];
   
   return A;

Пример

Јенов алгоритам, К=3, C до H
Јенов алгоритам, К=3, C до H

Овај пример користи Јенов алгоритам да израчуна 3 најкраће путање од (C) to (H). Дијкстрин алгоритам је искоршћен да се израчуна најбоља путања од (C) to (H), која је (C)(E)(F)(H) са ценом од 5. Ова путања је додата у A и постаје прва к-та најкраћа путања, A1.

Чвор (C) од A1 постаје споредни чвор са коренском путањом сачињеном од самог себе, R21=(C). Грана (C)(E) се уклања, јер се поклапа са коренском путањом и путањом у A. Дијкстра се користи да се израчуна споредна путања S21 које је (C)(D)(F)(H), са ценом 8. A21=R21+S21=(C)(D)(F)(H) се додају у B као потенцијална к-најкраћа путања.

Чвор (E) из A1 постаје споредни чвор са R22=(C)(E). Грана (E)(F) се уклања јер се поклапа са коренском путањом и путањом у A. Дијкстра се користи за израчунавање споредне путање S22, која је (E)(G)(H), са ценом 7. A22=R22+S22=(C)(E)(G)(H) се додаје у B као потенцијална к-најкраћа путања.

Чвор (F) из A1 постаје споредни чвор са R23=(C)(E)(F). Грана (F)(H) се уклања јер се поклапа са коренском путањом и путањом у A. Дијкстра се користи за израчунавање споредне путање S23, која је (F)(G)(H), са ценом 8. A23=R23+S23=(C)(E)(F)(G)(H) се додаје у B као потенцијална к-најкраћа путања.

Од три путање у B, A22 је одабрана да постане A2, јер има најмању цену од 7. Овај процес се наставља до 3. к-те најкраће путање. Међутим, у трећем понављању, неке споредне путање не постоје, а путања која је одабрана да постане A3 је (C)(E)(F)(G)(H).

Особине

Просторна сложеност

Да би се чувале гране графа, листа најкраћих путања A и листа потенцијалних најкраћих путања B, потребно је N2+KN меморије.[2] У најгорем случају, сваки чвор је повезан са свим осталим и тада нам треба N2 меморије. Само KN меморије је потребно за листе A и B, јер се чува највише K путања, максималне дужине N.[2]

Временска сложеност

Временска сложеност зависи од алгоритма за тражење најкраћег пута који се користи у израчунавању споредних путања, па се претпоставља да се користи Дијкстра алгоритам. Дијкстра има временску сложеност најгорег случаја O(N2), али ако се користи Фибоначијев хип оно постаје O(M+NlogN),[3] где је M број грана у графу. Пошто Јенов алгоритам има K позива Дијкстриног алгоритма у рачунању споредних путања, временска сложеност постаје O(KN(M+NlogN)).Шаблон:Sfn

Унапређења

Јенов алгоритам може бити унапређен коришћењем хипа за чување потенцијалних к-најкраћих путања у листи B. Коришћењем хипа уместо листе ће се побољшати брзина, али не и сложеност.[4] Један од начина за благо смањење сложености је да се прескоче чворови који немају споредне путање. Овај случај настаје када су све споредне путање из неког споредног чвора искоришћене у претходном Ak. Такође, ако B има Kk путања минималне дужине, у вези са путањама у A, онда их можемо убацити у A, јер више ниједна путања неће бити краћа.

Лолерово унапређење

Јуџин Лолер је предложио модификацију Јеновог алгоритма у коме се дупликати путања не израчунавају, за разлику од оригиналне идеје, где се они израчунавају, али се потом одбацују када се установи да су дупликати.[5] Ови дупликати настају када се рачунају споредне путање за чворове из корена од Ak. На пример Ak одступа од Ak1 у неком чвору (i). Свака споредна путања Skj где је j=0,,i, које се израчуна ће бити дупликат, јер су већ израчунате у k1 понављању. Због тога, потребно је израчунати само споредне путање за чворове који су део споредне путање од Ak1, тј. само Skh где h узима вредности од (i+1)k1 до (Qk)k1. Да би се ово урадило за Ak, потребно је негде забележити где се Ak1 одвојило од Ak2.

Референце

Шаблон:Reflist

Литература

Спољашње везе

Шаблон:Нормативна контрола