Різниця між алгоритмами Прима та Дейкстри?


95

Яка точна різниця між алгоритмами Дейкстри та Прима? Я знаю, що Prim's дасть MST, але дерево, створене Дейкстрою, також буде MST. Тоді в чому точна різниця?


5
Це Дейкстра. "ij" - це дифтонг (ковзаюча голосна) в голландській мові, і це єдине місце, де "j" не є приголосною.

23
будь-якими способами ви отримали запитання.
anuj pradhan

4
Найкращий спосіб розрізнити їх різницю - це прочитати якийсь вихідний код , Дейкстра та Прим . Головна відмінність тут: і для Прима graph[u][v] < key[v], і для Дейкстри dist[u]+graph[u][v] < dist[v]. Отже, як ви можете бачити з графіків на цих двох сторінках, вони різні, головним чином через ці два рядки коду.
JW.ZG

Відповіді:


150

Алгоритм Прима створює мінімальне охоплююче дерево для графіка, яке є деревом, яке з'єднує всі вузли в графіку і має найменшу загальну вартість серед усіх дерев, які з'єднують усі вузли. Однак довжина шляху між будь-якими двома вузлами в MST може бути не найкоротшим шляхом між цими двома вузлами у вихідному графіку. MST є корисними, наприклад, якщо ви хочете фізично підключити вузли на графіку, щоб забезпечити їх електроенергією за найменших загальних витрат. Немає значення, що довжина шляху між двома вузлами може бути не оптимальною, оскільки все, що вам важливо, це той факт, що вони з’єднані.

Алгоритм Дейкстри будує дерево найкоротшого шляху, починаючи з якогось вихідного вузла. Дерево найкоротшого шляху - це дерево, яке зв’язує всі вузли в графі назад із вихідним вузлом і має властивість зменшувати довжину будь-якого шляху від вихідного вузла до будь-якого іншого вузла на графіку. Це корисно, наприклад, якщо ви хочете побудувати дорожню мережу, яка зробила б максимально ефективним для всіх доступ до якоїсь важливої ​​важливої ​​пам’ятки. Однак дерево найкоротшого шляху не гарантовано є мінімальним охоплюючим деревом, і сума витрат по краях дерева найкоротшого шляху може бути набагато більшою, ніж вартість MST.

Інша важлива відмінність стосується того, на яких типах графіків працюють алгоритми. Алгоритм Прима працює лише на неорієнтованих графіках, оскільки концепція MST передбачає, що графіки за своєю суттю неорієнтовані. (Існує щось, що називається "мінімальним охоплюючим дендроценцією" для спрямованих графіків, але алгоритми їх пошуку набагато складніші). Алгоритм Дейкстри буде чудово працювати на спрямованих графіках, оскільки дерева найкоротшого шляху дійсно можуть бути спрямовані. Крім того, алгоритм Дейкстри не обов'язково дає правильне рішення в графіках, що містять від'ємні ваги ребер , тоді як алгоритм Прима може це впоратись.

Сподіваюся, це допомагає!


Перший абзац не має сенсу, чоловіче. Питання полягає в тому, в чому різниця між Дейкстрою та Примом, де Дейкстра - це не те, про що ви сказали the length of a path between **any** two nodes, вам слід просто зосередитись, чому відстань між вузлом src та будь-якими іншими вузлами в Примі не найкоротша, якщо вона не найкоротша. Я думаю, він, мабуть, запитує вузол src у Prim до будь-якого іншого вузла . Чому ви говорили про будь-які два вузли в Prim? Це, звичайно, не найкоротше.
JW.ZG

2
Я вичистив формулювання в параграфі про алгоритм Дейкстри, щоб пояснити, що дерево найкоротшого шляху - це лише мінімізатор для найкоротших шляхів, що походять з вихідного вузла. Причиною того, що я структурував свою відповідь, був спосіб проілюструвати, що алгоритми знаходять, а не те, як вони працюють, щоб показати на вищому рівні, чому вони дають різні результати і чому ви не очікуєте, що вони будуть однаковими.
templatetypedef

1
Найпростіше пояснення - у Prims ви не вказуєте початковий вузол , але в dijsktra вам (потрібно мати початковий вузол) потрібно знайти найкоротший шлях від даного вузла до всіх інших вузлів. Дивіться stackoverflow.com/a/51605961/6668734
Діпак Ядав

1
@templatetypedef - Коли ви говорите: "і вартість побудови такого дерева [за допомогою Дейкстри] може бути набагато більшою, ніж вартість MST". Ви можете, будь ласка, детальніше розказати?
Амеліо Васкес-Рейна

1
@ AmelioVazquez-Reina Вибачте, цей біт неоднозначний. Я мав на увазі, що сума ваг на краях дерева найкоротших шляхів може бути набагато більшою, ніж сума ваг на краях в MST.
templatetypedef

84

Алгоритм Дейкстри не створює MST, він знаходить найкоротший шлях.

Розглянемо цей графік

       5     5
  s *-----*-----* t
     \         /
       -------
         9

Найкоротший шлях - 9, тоді як MST - це інший "шлях" на 10.


2
Гаразд, дякую ... Ви зрозуміли хороший момент, щоб помітити. До цього часу я розглядав, що вихідний результат, створений dijkstra, буде MST, але ви зняли сумнів на гарному прикладі. Я чітко бачу, чи знайду я MST, використовуючи rec 'kruskal', тоді я отримаю той самий шлях, про який ви згадали . Велике спасибі
anuj pradhan

8
Правильніше - The shortest path is 9... від s до t. Вага графіка, породженого алгоритмом Дейкстри, починаючи з s, дорівнює 14 (5 + 9).
Бернхард Баркер,

1
@Dukeling - так? вага дерева / графіка у Дейкстри безглузда, це свого роду суть ....
dfb

4
Дуже лаконічно проілюстровано!
Рам Нарасимхан,

1
@dfb: Зазвичай ми запускаємо алгоритм Дейкстри лише для того, щоб отримати найкоротший шлях між певною парою вершин, але насправді ви можете продовжувати рухатися, поки всі вершини не будуть відвідані, і це дасть вам "дерево найкоротшого шляху", як відповідь templatetypedef пояснює.
j_random_hacker

65

Алгоритми Prim і Дейкстра майже однакові, за винятком "функції розслаблення".

Прим:

MST-PRIM (G, w, r) {
    for each key ∈ G.V
        u.key = ∞
        u.parent = NIL
    r.key = 0
    Q = G.V

    while (Q ≠ ø)
        u = Extract-Min(Q)
        for each v ∈ G.Adj[u]
            if (v ∈ Q)
                alt = w(u,v)    <== relax function, Pay attention here
                if alt < v.key
                    v.parent = u
                    v.key = alt
}

Дейкстра:

Dijkstra (G, w, r) {
    for each key ∈ G.V
        u.key = ∞
        u.parent = NIL
    r.key = 0
    Q = G.V

    while (Q ≠ ø)
        u = Extract-Min(Q)
        for each v ∈ G.Adj[u]
            if (v ∈ Q)
                alt = w(u,v) + u.key  <== relax function, Pay attention here
                if alt < v.key
                    v.parent = u
                    v.key = alt
}

Єдину різницю вказує стрілка, яка є функцією розслаблення.

  • Prim, який шукає мінімальне дерево, що охоплює, дбає лише про мінімум загальних ребер, що охоплюють усі вершини. Функція розслаблення єalt = w(u,v)
  • Дійкстра, яка шукає мінімальну довжину шляху, тому вона дбає про накопичення краю. Функція розслаблення єalt = w(u,v) + u.key

На рівні коду іншою відмінністю є API. Prim має метод edges()повернення MST-ребер, тоді як Dijkstra має distanceTo(v), pathTo(v)який, відповідно, повертає відстань від джерела до вершини v і шлях від джерела до вершини v, де s - вершина, з якою ініціалізується Дейкстра.
nethsix

1
Слідство, инициализирует Прима з будь-яким з будь-якого джерела вершини, з повертає той же результат для edges(), але ініціалізації Дейкстри з різними з повернеться до різних результатів distanceTo(v), pathTo(v).
nethsix

Чи дозволяють грунтовки негативну вагу? якщо так, то це ще одна різниця. Я читав, що ви можете дозволити від’ємні ваги на простих, додавши великі позитивні ні. до кожного значення, роблячи все це позитивним.
Akhil Dad

1
Вирішив мою плутанину! Ідеальна відповідь !!
Dhananjay Sarsonia

тут оброблена вершина повинна бути проігнорована для неорієнтованого графіка
пан Ей Джей,

53

Алгоритм Dijsktra знаходить мінімальну відстань від вузла i до всіх вузлів (ви вказуєте i). Отже, натомість ви отримуєте дерево мінімальної відстані від вузла i.

Алгоритм Prims отримує мінімальне дерево охоплення для даного графіка . Дерево, яке з'єднує всі вузли, тоді як сума всіх витрат є мінімально можливою.

Так і з Дейкстрою ви можете перейти від вибраного вузла до будь-якого іншого з мінімальними витратами , ви не отримаєте цього за допомогою Prim


Найпростіше пояснення - у Prims ви не вказуєте початковий вузол , але в dijsktra вам (потрібно мати початковий вузол) потрібно знайти найкоротший шлях від даного вузла до всіх інших вузлів. Дивіться stackoverflow.com/a/51605961/6668734
Діпак Ядав

32

Єдина різниця, яку я бачу, полягає в тому, що алгоритм Прима зберігає границю мінімальних витрат, тоді як алгоритм Дейкстри зберігає загальну вартість від вихідної вершини до поточної вершини.

Дейкстра дає вам шлях від вузла-джерела до вузла призначення таким чином, що вартість буде мінімальною. Однак алгоритм Prim дає вам мінімальне дерево, що охоплює, так що всі вузли з'єднані, а загальна вартість мінімальна.

Простими словами:

Отже, якщо ви хочете розгорнути поїзд для сполучення кількох міст, ви скористаєтесь альго Прима. Але якщо ви хочете переїхати з одного міста в інше, щоб заощадити якомога більше часу, ви можете скористатися альго Дейкстри.


24

Обидва вони можуть бути реалізовані з використанням точно такого ж загального алгоритму, як описано нижче:

Inputs:
  G: Graph
  s: Starting vertex (any for Prim, source for Dijkstra)
  f: a function that takes vertices u and v, returns a number

Generic(G, s, f)
    Q = Enqueue all V with key = infinity, parent = null
    s.key = 0
    While Q is not empty
        u = dequeue Q
        For each v in adj(u)
            if v is in Q and v.key > f(u,v)
                v.key = f(u,v)
                v.parent = u

Для Prim, пас f = w(u, v)і для Dijkstra пасf = u.key + w(u, v) .

Інша цікава річ, що вище Generic може також реалізувати Breadth First Search (BFS), хоча це було б надмірним, оскільки дорога черга пріоритетів насправді не потрібна. Щоб перетворити вище загального алгоритму на BFS, передайте f = u.key + 1той самий, що примусити всі ваги до 1 (тобто BFS дає мінімальну кількість ребер, необхідних для проходження від точки A до B).

Інтуїція

Ось один хороший спосіб подумати про вищезазначений загальний алгоритм: ми починаємо з двох сегментів A і B. Спочатку покладіть всі ваші вершини в B, щоб сегмент A був порожнім. Потім ми переміщаємо одну вершину з В в А. Тепер подивимось на всі ребра з вершин А, що переходять до вершин Б. Ми вибрали одне ребро, використовуючи деякі критерії з цих перехресних ребер, і перемістимо відповідну вершину з В в A. Повторюйте цей процес, поки B не порожній.

Грубим способом реалізації цієї ідеї було б підтримання черги пріоритетів ребер для вершин А, яка переходить до Б. Очевидно, це було б складно, якби графік не був розрідженим. Тож питання буде, чи можемо ми замість цього підтримувати пріоритетну чергу вершин? Це насправді ми можемо зробити, оскільки врешті-решт ми вирішили, яку вершину вибрати з B.

Історичний контекст

Цікаво, що загальна версія техніки, що лежить в основі обох алгоритмів, концептуально стара як 1930, навіть коли електронних комп’ютерів не було поруч.

Історія починається з Отакара Борівки, якому потрібен був алгоритм для сімейного друга, який намагався з’ясувати, як з’єднати міста в країні Моравія (нині частина Чеської Республіки) мінімальними електричними лініями. Він опублікував свій алгоритм у 1926 році у журналі, пов’язаному з математикою, оскільки тоді комп’ютерних наук не існувало. Це звернуло увагу на Войтеха Ярника, який задумав вдосконалити алгоритм Борівки та опублікував його в 1930 році. Він фактично відкрив той самий алгоритм, який ми зараз знаємо як алгоритм Прима, який знову його відкрив у 1957 році.

Незалежно від усього цього, в 1956 році Дейкстрі потрібно було написати програму, щоб продемонструвати можливості нового комп'ютера, розробленого його інститутом. Він вважав, що було б круто мати комп’ютер, щоб знайти зв’язок для подорожі між двома містами Нідерландів. Він розробив алгоритм за 20 хвилин. Він створив графік 64 міст з деякими спрощеннями (оскільки його комп’ютер був 6-розрядним) і написав код для цього комп’ютера 1956 року. Однак він не опублікував свій алгоритм, оскільки в першу чергу не було журналів з інформатики, і він вважав, що це може бути не дуже важливим. Наступного року він дізнався про проблему підключення клем нових комп'ютерів таким чином, щоб довжина проводів була мінімізована. Він задумався над цією проблемою і знову відкрив Ярніка / Прима алгоритм, який знову використовує ту саму техніку, що і алгоритм найкоротшого шляху, який він відкрив роком раніше. Вінзгадав, що обидва його алгоритми були розроблені без використання ручки чи паперу. У 1959 році він опублікував обидва алгоритми у статті, яка займає лише 2 з половиною сторінки.


Дякую! Вихід туманний, чому він виходить із циклу, навіть якщо нічого не відбувається?
amirouche

15

Дейкстра знаходить найкоротший шлях між початковим вузлом та кожним іншим вузлом. Отже, натомість ви отримуєте дерево мінімальної відстані від початкового вузла, тобто ви можете досягти кожного іншого вузла якомога ефективніше.

Алгоритм Prims отримує MST для даного графіка, тобто дерева, яке з'єднує всі вузли, тоді як сума всіх витрат є мінімально можливою.

Щоб коротко розповісти на реалістичному прикладі:

  1. Дейкстра хоче знати найкоротший шлях до кожної точки призначення, заощаджуючи час у дорозі та паливо.
  2. Prim хоче знати, як ефективно розгорнути залізничну залізничну систему, тобто заощадити матеріальні витрати.

10

Безпосередньо зі статті Вікіпедії Алгоритму Дейкстри :

Процес, який лежить в основі алгоритму Дейкстри, подібний до жадібного процесу, що використовується в алгоритмі Прима. Мета Prim - знайти мінімальне дерево, що охоплює, що з'єднує всі вузли на графіку; Дейкстра стосується лише двох вузлів. Prim не визначає загальну вагу шляху від початкового вузла, а лише окремий шлях.


5
"Дейкстра стосується лише двох вузлів" є етапом.
tmyklebu

5

Останнім часом мене турбувало одне і те ж питання, і я думаю, що, можливо, поділюся своїм розумінням ...

Я думаю, що ключова різниця між цими двома алгоритмами (Дейкстра та Прим) коренева в проблемі, яку вони призначені вирішувати, а саме в найкоротшому шляху між двома вузлами та мінімальним охоплюючим деревом (MST). Формальним є пошук найкоротшого шляху між скажем, вузлом s і t , а раціональною вимогою є відвідування кожного краю графіка не більше одного разу. Однак це НЕ вимагає від нас відвідування всього вузла. Останній (MST) - змусити нас відвідати ВСІ вузли (принаймні один раз) і з однаковою раціональною вимогою також відвідувати кожен край щонайменше одноразово.

З огляду на це, Дейкстра дозволяє нам "приймати ярлик" так довго, щоб я міг переходити від s до t , не турбуючись про наслідки - як тільки я доберуся до t , я закінчу! Хоча в MST також є шлях від s до t , але цей s - t шлях створюється з урахуванням усіх інших вузлів, отже, цей шлях може бути довшим, ніж s - t шлях, знайдений алгоритмом Дійстри. Нижче наведено короткий приклад з 3 вузлами:

                                  2       2  
                          (s) o ----- o ----- o (t)     
                              |               |
                              -----------------
                                      3

Скажімо, кожен верхній край має вартість 2, а нижній край коштує 3, тоді Dijktra скаже нам пройти нижній шлях, оскільки ми не дбаємо про середній вузол. З іншого боку, Prim поверне нам MST з верхніми 2 краями, відкинувши нижній край.

Така різниця відображається також на тонкій різниці в реалізаціях: в алгоритмі Дейкстри потрібно мати крок ведення книги (для кожного вузла), щоб оновити найкоротший шлях із s , після поглинання нового вузла, тоді як в алгоритмі Прима немає такої потреби.


3

Ключова відмінність між основними алгоритмами полягає в їх різних критеріях вибору краю. Як правило, вони обидва використовують пріоритетну чергу для вибору наступних вузлів, але мають різні критерії для вибору сусідніх вузлів поточних вузлів обробки: Алгоритм Prim вимагає, щоб наступні сусідні вузли також повинні зберігатися в черзі, тоді як Алгоритм Дейкстри не:

def dijkstra(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            ...

def prim(g, s):
    q <- make_priority_queue(VERTEX.distance)
    for each vertex v in g.vertex:
        v.distance <- infinite
        v.predecessor ~> nil
        q.add(v)
    s.distance <- 0
    while not q.is_empty:
        u <- q.extract_min()
        for each adjacent vertex v of u:
            if v in q and weight(u, v) < v.distance:// <-------selection--------
            ...

Обчислення відстані vertex.distance є другою різною точкою.


3

Алгоритм Дейкстри є єдиною проблемою найкоротшого шляху між вузлом i та j, але алгоритм Прима - мінімальна проблема, що охоплює дерево. Ці алгоритми використовують концепцію програмування під назвою `` жадібний алгоритм ''

Якщо ви перевірите це поняття, будь ласка, відвідайте

  1. Примітка лекції про жадібний алгоритм: http://jeffe.cs.illinois.edu/teaching/algorithms/notes/07-greedy.pdf
  2. Мінімальне дерево, що охоплює: http://jeffe.cs.illinois.edu/teaching/algorithms/notes/20-mst.pdf
  3. Короткий шлях до одного джерела: http://jeffe.cs.illinois.edu/teaching/algorithms/notes/21-sssp.pdf

2

Алгоритм Дейкстраса використовується лише для пошуку найкоротшого шляху.

У дереві мінімального розмаху (алгоритм Прима або Крускала) ви отримуєте мінімальний приклад із мінімальним значенням краю.

Наприклад: - Розглянемо ситуацію, коли ви не хочете створювати величезну мережу, для якої вам знадобиться велика кількість проводів, тому цей підрахунок дроту можна виконати, використовуючи мінімальне дерево розмаху (алгоритм Прима або Крускала) (тобто це буде дати вам мінімальну кількість проводів для створення величезного дротового мережевого з'єднання з мінімальними витратами).

Тоді як "алгоритм Дейкстраса" буде використаний для отримання найкоротшого шляху між двома вузлами при одночасному з'єднанні будь-яких вузлів між собою.


2

Найпростіше пояснення - у Prims ви не вказуєте початковий вузол , але в dijsktra вам (потрібно мати початковий вузол) потрібно знайти найкоротший шлях від даного вузла до всіх інших вузлів.


0

@templatetypedef охопив різницю між MST та найкоротшим шляхом. Я розглянув різницю в алгоритмі в іншому Отже, відповідь , продемонструвавши, що обидва вони можуть бути реалізовані за допомогою одного загального алгоритму, який приймає ще один параметр як вхід: функція f(u,v). Різниця між алгоритмом Прима і Дейкстри полягає просто в тому, що f(u,v)ви використовуєте.


0

На рівні коду іншою відмінністю є API.

Ви ініціалізуєте Prim з вихідною вершиною, s , тобто Prim.new(s); s може бути будь-якою вершиною, і, незалежно від s , кінцевий результат, який є ребрами мінімального охоплюючого дерева (MST), однаковий. Щоб отримати ребра MST, ми викликаємо метод edges().

Ви ініціалізуєте Дейкстру вихідною вершиною s , тобто, Dijkstra.new(s)що ви хочете отримати найкоротший шлях / відстань до всіх інших вершин. Кінцеві результати - це найкоротший шлях / відстань від s до всіх інших вершин; різні в залежності від s . Щоб отримати найкоротший шлях / відстань від s до будь-якої вершини, v , ми викликаємо методи distanceTo(v)і pathTo(v)відповідно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.