Menu
Coddy logo textTech

אלגוריתם Bellman-Ford

עודכן לאחרונה

Bellman-Ford מוצא את המסלול הקצר ביותר מצומת מקור לכל צומת אחר, ובניגוד ל-Dijkstra הוא עובד גם כשחלק ממשקלי הקשתות שליליים. הוא פועל בריכוך בכוח גס: הוא סורק שוב ושוב כל קשת, ואם מעבר דרכה נותן מרחק קצר יותר, הוא מעדכן את המרחק של צומת היעד. לחצו על הפעלה למעלה כדי לראות את המרחקים הזמניים יורדים סבב אחר סבב.

אחרי V - 1 סבבים על כל הקשתות, כל מסלול קצר ביותר (שיש בו לכל היותר V - 1 קשתות) כבר נמצא. לכן הסיבוכיות היא O(V · E), איטי יותר מ-Dijkstra, אבל הוא מתמודד עם משקלים שליליים ויכול לזהות מעגל במשקל שלילי (אם סבב מספר V עדיין מרכך קשת, אין מסלול קצר ביותר).

סיבוכיות זמן וזיכרון

מדדסיבוכיותהערות
זמןO(V · E)V − 1 סבבים על כל E הקשתות
זיכרוןO(V)מרחק אחד לכל צומת
משקלים שלילייםנתמכיםהיתרון המרכזי שלו על פני Dijkstra
מעגלים שלילייםניתנים לזיהויסבב מספר V שעדיין מרכך מעיד על מעגל כזה

צעד אחר צעד

צעדמה קורה
1קובעים את מרחק המקור ל-0 ואת כל השאר לאינסוף.
2חוזרים על הצעד הבא V − 1 פעמים.
3לכל קשת (u → v, w), בודקים אם dist[u] + w < dist[v].
4אם כן, מרככים אותה: dist[v] = dist[u] + w.
5עוצרים מוקדם אם סבב שלם לא שינה כלום.

דוגמה מפורטת

מקור S בגרף עם 4 צמתים S, A, B, C וקשתות S→A (4), S→B (5), A→C (3), B→A (-3), שמרוככות בסדר הזה. המרחקים מתחילים ב-S=0 וכל השאר ∞:

סבבמרחקים [S, A, B, C]פעולה
אתחול[0, ∞, ∞, ∞]מרחק המקור הוא 0, כל השאר אינסוף.
1[0, 2, 5, 7]מרככים את S→A ל-4, את S→B ל-5, את A→C ל-7, ואז B→A מוריד את A ל-5 + (-3) = 2.
2[0, 2, 5, 5]A→C משפר עכשיו את C ל-2 + 3 = 5; אף קשת אחרת לא מתרככת.
3[0, 2, 5, 5]אף קשת לא מתרככת, ולכן המרחקים סופיים: A עולה 2 דרך S→B→A.

מתי להשתמש ב-Bellman-Ford

השתמשו בו כאשרהימנעו ממנו כאשר
משקלי הקשתות יכולים להיות שליליים.כל המשקלים אי שליליים (Dijkstra מהיר יותר).
אתם חייבים לזהות מעגלים במשקל שלילי.הגרף ענק וצפוף: O(V · E) איטי מדי.
הגרף קטן או דליל.אתם צריכים רק שאילתה אחת ממקור ליעד בגרף גדול.
אתם צריכים פתרון בסיס פשוט וקל למימוש.המשקלים אי שליליים וזמן התגובה חשוב.

קוד Bellman-Ford Algorithm

מימוש נקי של Bellman-Ford Algorithm שאפשר להריץ, ב-Python, JavaScript, Java, C++, C. בחרו שפה, העתיקו את הקוד, או פתחו אותו טעון מראש בעורך האונליין של Coddy.

קוד Bellman-Ford Algorithm ב-Python

Python
1def bellman_ford(vertices, edges, start):2    dist = {v: float("inf") for v in vertices}3    dist[start] = 04    # Relax every edge V-1 times5    for _ in range(len(vertices) - 1):6        for u, v, w in edges:7            if dist[u] + w < dist[v]:8                dist[v] = dist[u] + w9    # One more pass: any improvement means a negative cycle10    for u, v, w in edges:11        if dist[u] + w < dist[v]:12            raise ValueError("Graph contains a negative-weight cycle")13    return dist14
15
16vertices = ["A", "B", "C", "D", "E"]17edges = [18    ("A", "B", 6), ("A", "C", 7), ("B", "D", 5), ("B", "E", -4),19    ("C", "D", -3), ("D", "B", -2), ("E", "D", 7),20]21
22for node, d in bellman_ford(vertices, edges, "A").items():23    print(f"A -> {node}: {d}")
להריץ את הקוד הזה בעורך ה-Python אונליין

שאלות נפוצות על Bellman-Ford

מהי סיבוכיות הזמן של Bellman-Ford?
Bellman-Ford רץ בזמן O(V · E): הוא מבצע V - 1 סבבים, ובכל סבב מרכך את כל E הקשתות. זה איטי יותר מ-O((V + E) log V) של Dijkstra, וזה המחיר של תמיכה במשקלי קשתות שליליים.
מתי כדאי להשתמש ב-Bellman-Ford במקום ב-Dijkstra?
השתמשו ב-Bellman-Ford כשבגרף יכולים להיות משקלי קשתות שליליים, או כשצריך לזהות מעגלים במשקל שלילי. Dijkstra מהיר יותר אבל נכון רק עם משקלים אי שליליים. שימוש נפוץ בעולם האמיתי הוא זיהוי ארביטראז' בהמרת מטבעות, שבו מעגלים שליליים חשובים.
איך Bellman-Ford מזהה מעגל שלילי?
אחרי V - 1 סבבי הריכוך, כל המסלולים הקצרים ביותר סופיים אם אין מעגל שלילי. אם סבב נוסף עדיין יכול לרכך קשת, סימן שאפשר להגיע למעגל במשקל שלילי, והמסלולים הקצרים ביותר אינם מוגדרים (אפשר להסתובב בלולאה לנצח ולהוריד את העלות).
מה ההבדל בין Bellman-Ford ל-Floyd-Warshall?
Bellman-Ford מחשב מסלולים קצרים ביותר ממקור יחיד ב-O(V · E), ואילו Floyd-Warshall מחשב מסלולים קצרים ביותר בין כל הזוגות ב-O(V³). בגרף צפוף, הרצת Bellman-Ford מכל מקור עולה O(V² · E), ולכן Floyd-Warshall הוא בדרך כלל הבחירה הטובה יותר כשצריך כל זוג. שניהם מתמודדים עם קשתות שליליות ויכולים לזהות מעגלים שליליים.
למה Bellman-Ford צריך בדיוק V - 1 סבבים?
כל מסלול קצר ביותר בגרף בלי מעגל שלילי משתמש לכל היותר ב-V - 1 קשתות, כי מסלול שעובר ביותר מ-V צמתים חייב לחזור על אחד מהם. כל סבב מבטיח שלפחות קשת אחת נוספת בכל מסלול קצר ביותר מרוככת נכון, ולכן V - 1 סבבים מספיקים כדי לקבע את כולם. טעות נפוצה היא לחשוב שעוד סבבים משפרים את התשובה: הם אף פעם לא משפרים, אלא אם קיים מעגל שלילי.
האם Bellman-Ford יכול לעצור מוקדם?
כן. אם סבב שלם על כל הקשתות לא מרכך כלום, כל מרחק כבר אופטימלי ואפשר לעצור לפני שמגיעים ל-V - 1 סבבים. אופטימיזציית היציאה המוקדמת הזו הופכת אותו לעתים קרובות למהיר הרבה יותר בגרפים שמתכנסים מהר, אם כי החסם במקרה הגרוע נשאר O(V · E).
איור של שפות התכנות ב-Coddy

לשלוט באלגוריתמים עם Coddy

להתחיל