בהינתם גרף, הסריקה
בהינתן גרף מכוון
בדומה לאלגוריתם ה BFS גם האלגוריתם DFS משייך במהלך ריצתו לכל קודקוד אחד משלושה צבעים
שמסמלים את מצב הקודקוד.
לבן - טרם ביקרנו בקודקוד
אפור - ביקרנו אך טרם סיימנו לטפל
שחור - ביקרנו וסיימנו לטפל
כמו כן , לכל קודקוד נשמור שלושה ערכים
נשים לב שיער העומק תלוי בריצה הספציפית של האלגוריתם
בשונה מBFS האלגוריתם של DFS תמיד סורק את כל הגרף, בעוד ש BFS סורק רק את הקודקודים הנגישים מקודקוד מקור.
DFS(G)
if u in V
color[u] = w
parent[u] = null
// t is some sort of timestamp
t=0
for u in V
if color[u] = w
DFS-Visit(u)
DFS-Visit(u)
color[u] = g
t = t+1
d[u] = t
for v in adj(u)
if color[v] = w
DFS-Visit(v)
parent[v] = u
color[u] = b
t = t+1
f[u] = t
באלגוריתם הזה אנחנו סורקים עבור קודקוד מסוים את העומק הכי נמוך שנוכל ״לרדת״ כלומר מייצרים יער עומק הנמוך ביותר לפני שנלך לשכנים האחרים.
זמן הריצה הוא
בכל חיפוש לעומק על גרף
עבור כל זוג קודקודים
מסקנה : קודקוד
נוכיח את שתי הכיוונים

נשים לב שבזמן שביקרנו את
שלפי משפט הסוגריים זה נכון אמ״מ
הגדרה: גרף מכוון ללא מעגלים או
בהינתן גמ״ל נרצה סידור מיוחד של הקודקודים משמאל לימין שבו כל הקשתות הן בכיוון משמאל לימין. כלומר עבור גרף
של הקודקודים ב
במילים יפות, זה אומר שנרצה שלאחר מיון נשים את כל הקודקודים לפי הסדר שקיבלנו בשורה וכל הקשתות יופנו לימין .

בגלל זה גם האלגוריתם עובד רק על גרף מכוון ללא מעגלים כי מצב כמו למעלה לא ייתכן, תמיד יהיה חץ אחד שמאלה לפחות.
נשים לב שכל מה שהמיון הזה נותן זה איזה סידור מסויים של הקודקודים כאשר אנחנו יודעים שיש מסלול מקודקוד שמאלי לקודקוד ימני באיזשהו אופן. למשל עבור הגרף:

ניתן לראות ש קודקוד מספר 1 הוא שכן של 2 ו3 ולכן הוא יהיה לפניהם בסידור והם שכנים של 4 ולכן הם מופיעים לפניו וכן הלאה כלומר אם נסדר את הגרף במיון טופולוגי נקבל משהו כזה:

משפט עזר: גרף מכוון לא מכיל מעגלים אמ״מ בריצת DFS אין קשתות אחורה.
הוכחה - אם לגרף אין מעגלים אז בסריקת DFS לעולם לא נבקר בקודקוד שכבר ביקרנו בו, כלומר, כל הקשתות בDFS יהיו קשתות של עץ של רכיב הקשירות של הקודקוד ממנו התחלנו את הסריקה, משמע אין לנו קשת אחורה. מצד שני, אם לגרף אין קשתות אחורה לא יכול להיווצר מעגל, כי בהגדרת קשת אחורה היא קשת שמחברת בין קודקוד לבין קודקוד אחר שכבר נסרק בסריקת DFS כלומר קודקוד אב. אם בסריקה אין לנו קשתות כאלה זה אומר שמראש כל הרכיבי קשירות של הגרף הן עץ כלומר אין מעגלים באף רכיב קשירות כדרוש.
תזכורת, קשת אחורה היא מהצורה:

ההוכחה הנ״ל מופשטת אבל נוכל לשים לב לדרך מאוד פשוטה לזהות קשתות אחורה.
קשת
אם כן מיון טופולוגי של קודקודי גמ״ל
Topological-Sort(G):
DFS(G)
return sorted V by f[u] in decreasing order
זמן הריצה הוא
ניקח קשת מהצורה הנ״ל ונרצה להוכיח ש
נפריד לשני מקרים:
א) אם
ב) אם
שזה בידיוק מה שרצינו.
או שיש הכלה ובגלל הנתון היא תהיה
כלומר ישנה הכלה לא שווה ולכן
בגרפים לא מכוונים הגדרנו רכיבי קשירות כקבוצות מקסימומיות כך שקיים מסלול בין כל זוג קודוקדים בקבוצה. בגרפים מכוונים המסלולים חייבים להיות מכוונים.
נגדיר רכיב קשיר היטב/ רכיב קשירות חזק
כלומר , קיים מסלול ב

נגיד ש
הגדרה: נגדיר את גרף ה SCC על

נראה אלגוריתם ליניארי למציאת רכיבי הקשירות החזקה
נתחיל מלחשוב על אלגוריתם הDFS. כאשר מריצים את אלגוריתם הDFS על גרף לא מכוון מקבלים יער, שבו העצים הם בדיוק רכיבי הקשירות של G. למה? כי מרגע שהפונקציה הראשית הביאה אותנו לקודקוד, אנו סורקים ע״פ משפט המסלול הלבן את כל מי שאיתו באותו רכיב. ומצד שני כמובן שלא ניתן להגיע מרכיב אחד לשני בלי לחזור ללואה בפונקציה הראשית.
מה יקרה אם נריץ את אלגוריתם ה־DFS על גרף מכוון? אנו כמובן עוברים לדבר על רכיבי קשירות חזקה. באופן דומה למצב בגרף לא מכוון ־ מרגע שהאלגוריתם מגיע לקודקוד כלשהו, הוא יסרוק את כל הרכיב הקשיר החזק שלו (ע״פ משפט המסלול הלבן ־ כל הקודקודים ברכיב הקשיר החזק יהיו בעץ), אולם ייתכן שיהיו בעץ גם קודקודים נוספים, כלומר כאלה שלא שייכים לאותו רכיב למשל בתמונה למטה, ניתן לראות שהעץ השמאלי הוא לא רכיב קשיר חזק היטב.

משפט : עבור גרף מכוון
הוכחה:
יהי
אם כן מטרתנו היא למצוא שיטה להריץ את הDFS בסדר כלשהו שבו נקבל שיש שרק רכיב קשירות חזק אחד נמצא בכל עץ ללא חשד שיש קודקודים נוספים
בשביל להגיע לתוצאה הרצויה הזאת נעבוד עם הגרף המשוחלף.
הגדרה: הגרף המשוחלף של
ניתן להגדיר את הגרף המשוחלף , בהינתן שהגרף מיוצג כמטריצת שכנויות , כשחלוף של המטריצה עצמה.
נשים לב שלשתי הגרפים יש בידיוק את אותם רכיבי קשירות (לא בעיה להוכיח זאת על ידי כך שמניחים בשלילה שבגרף המשוחלף ישנו איזה רכיב קשירות שלא קיים בגרף המקורי ואז ניקח מסלול כלשהו ברכיב קשירות החדש ובגרף המקורי נקבל שעדיין יש מסלול הפוך, בסתירה).
האלגוריתם ינצל את העובדה שהוא יכול למצוא את רכיבי הקשירות החזקה בכל אחד משני הגרפים, ויריץ שתי ריצות של DFS.
הריצה הראשונה תתבצע על הגרף המקורי, ובה האלגוריתם יבצע את בחירות הקודקודים באופן שרירותי. בריצה השניה (על הגרף המשוחלף) נרצה לבצע את בחירת הקודקודים בצורה מסוימת, שתבטיח לנו שכל עץ ביער העומק יכיל רק רכיב קשיר חזק אחד. לצורך חישוב זה נוכל להעזר במידע שחישבנו בריצת ה־DFS הראשונה ( על הגרף המקורי ).
לפי המשפט שטענו למעלה, הבעיה היחידה בפלט של DFS עלולה להיות שיהיה עץ שיכיל יותר מרכיב אחד. ננסה לנתח את האפשרות הזאת.
נסתכל על עץ
אנחנו יודעים ש
נוכיח בהמשך את הטענה שאם בגרף
המטרה שלנו היא להבטיח ש
כדי להבין איך נוכל להבטיח את ההבטחה הנ״ל, נחשוב על ריצת DFS הראשונה על הגרף
באופן הזה מובטח שבסריקת
SCC(G)
DFS(G) \\this it only to calculate f[v]
calculate G_T
run DFS(G_T) where V is sorted by f[v] in decreasing order
every tree in the forset is one SCC
למה: יהי
אם קיים מסלול
הוכחה:
על פי הנתון קיים מסלול
יהיו
אם שניהם שייכים לאותו רכיב אז קיים מסלול בין שניהם משני הכיוונים ולכן
נניח בלי הגבלת הכלליות ש
וגם
כלומר מצאנו שיש מסלול בינהם משני הכיוונים כלומר הם באותו רכיב קשיר היטב. כלומר קודקודי
הגדרה: יהי
למה:
עבור
אזי מתקיים
נחלק למקרים
א)
בזמן
ובפרט עבור
ב) אם
נניח בשלילה ש
מסקנה מיידית היא שבגרף המשוחלף :
משפט נכונות האלגוריתם:
כעת ניתן להוכיח שעבור גרף מכוון
נוכיח שכל עץ ביער העומק הוא רכיב קשיר היטב.
אנחנו כבר יודעים שכל רכיב קשיר מוכל בעץ. כעת , נניח בשלילה שיש עץ ביער העומק של ריצת ה DFS השנייה שמכיל לפחות שני רכיבי קשירות חזקים שונים.
ניקח את
בעץ יש לפחות שני רכיבי קשירות כלומר קיימת קשת שמחברת בין הרכיבים ונסמן אותה
האלגוריתם סורק את הקודקודים בסדר יורד לפי
ומצד שני , מהמסקנה נקבל שבגרף המשוחלף