You are on page 1of 65

‫סריקה לעומק‬

‫פרק ‪ 3‬ב‪Kleinberg/Tardos-‬‬
‫פרק ‪ 23.3-5‬ב‪Cormen et al-‬‬
‫רכיבים אי‪-‬פריקים‬
‫רכיבים קשירים היטב‬
‫מיון טופולוגי‬

‫‪1‬‬
‫קשירות‬

‫נעיין שוב בבעיית הקשירות‪:‬‬


‫ל‪?t-‬‬
‫האם יש מסלול מ‪t ss-‬‬

‫‪2‬‬
‫קשירות‬

‫נעיין שוב בבעיית הקשירות‪:‬‬


‫ל‪?t-‬‬
‫האם יש מסלול מ‪t ss-‬‬

‫‪s‬‬ ‫‪t‬‬

‫‪2‬‬
‫כשלון הגישה החמדנית‬

‫‪s‬‬ ‫‪t‬‬

‫‪3‬‬
‫כשלון הגישה החמדנית‬

‫‪s‬‬ ‫‪t‬‬

‫‪3‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
‫תיקון‬

‫‪s‬‬ ‫‪t‬‬

‫כשנתקעים במבוי סתום‪ ,‬נבטל את הצעד האחרון‬


‫שנכשל‪ ,‬וננסה כיוון התקדמות אחר‪.‬‬
‫‪4‬‬
connectivity(G,s,t)
for each x ∈ V do pre[x]←∞, post[x]←∞, from[x]←nil
pre_c ← 0, post_c ← 0
DFS(G,s)
return pre[t] < ∞

DFS(G,x) (DFS) ‫סריקה לעומק‬


pre[x] ← pre_c++ x ‫בצעד הזה מגלים את‬
for each y ∈ Adj[x] do
if pre[y] = ∞ then ‫בצעד הזה נאמר‬
from[y] ← x ‫( נסרקה‬x,y) ‫שהקשת‬
DFS(G,y)
end if x-‫בצעד הזה חוזרים מ‬
end for
post[x] ← post_c++ pre[x] :‫סדר הגילוי‬
end DFS post[x] :‫סדר החזרה‬
5
‫סיבוכיות‬

‫אתחול‪O(|V|) :‬‬
‫מבצעים )‪ DFS(G,x‬לכל היותר פעם אחת לכל ‪.x‬‬
‫נחייב את הקריאה ל‪ DFS(G,x)-‬על ‪.x‬‬
‫למעט הקריאות הרקורסיביות‪ DFS(G,x) ,‬עולה )|]‪O(1)+O(|Adj[x‬‬
‫סה”כ‪O(|V|) + ∑x∈V {O(1) + O(|Adj[x]|)} = O(|V|+|E|) :‬‬

‫‪6‬‬
‫סיווג הקשתות‬

‫הקשתות הנסרקות נחלקות לארבעה סוגים‪ .‬קשת‬


‫שנסרקה )‪ (x,y‬היא‪:‬‬
‫קשת עץ‪ ,‬אם ‪) from[y] = x‬כלומר‪ ,‬סריקתה גילתה את ‪.(y‬‬
‫קשת קדימה‪ ,‬אם איננה קשת עץ‪ ,‬אבל ‪ y‬נתגלה בין גילוי ‪ x‬לחזרה‬
‫מ‪.x-‬‬
‫קשת אחורה‪ ,‬אם ‪ x‬נתגלה בין גילוי ‪ y‬לחזרה מ‪.y-‬‬
‫קשת הצידה‪ ,‬אם האפשרויות האחרות לא נתקיימו‪.‬‬

‫הגרף ‪ TDFS‬הנפרש על ידי קשתות העץ הוא עץ מכוון ששורשו ‪,s‬‬


‫והוא פורש את כל הצמתים הנגישים מ‪.s-‬‬

‫‪7‬‬
‫הדגמה‬
‫זוגות המספרים על הצמתים‪:‬‬ ‫המספרים על הקשתות‪:‬‬
‫סדר הגילוי וסדר החזרה‪.‬‬ ‫סדר הסריקה‪.‬‬

‫‪1, 8‬‬ ‫‪2‬‬ ‫‪2, 3‬‬ ‫‪3‬‬ ‫‪3, 2‬‬ ‫‪4‬‬ ‫‪4, 1‬‬
‫‪1‬‬
‫‪0, 9‬‬ ‫‪7‬‬ ‫‪9‬‬ ‫‪6‬‬ ‫‪5‬‬
‫‪13‬‬
‫‪7, 4‬‬ ‫‪8 6, 7 10‬‬ ‫‪8, 6 11‬‬ ‫‪5, 0‬‬

‫קשתות עץ‬ ‫‪12‬‬


‫קשתות קדימה‬
‫קשתות אחורה‬
‫קשתות הצידה‬ ‫‪9, 5‬‬
‫‪8‬‬
‫הערות‬

‫אפשר להריץ את האלגוריתם על גרף לא מכוון‪.‬‬


‫• כל קשת }‪ {x,y‬תיסרק בשני כיוונים‪ :‬מ‪ x-‬ל‪ y-‬ומ‪ y-‬ל‪.x-‬‬
‫• רק הסריקה הראשונה יכולה לגלות צומת חדש‪.‬‬

‫‪ .1‬הוכיחו כי בסריקה לעומק של גרף לא מכוון אין קשתות‬


‫הצידה‪) .‬הערה‪ :‬בגרף לא מכוון אין הבדל בין קשתות קדימה‬
‫וקשתות אחורה ‪ -‬שכנעו את עצמכם שכל הקשתות הללו נסרקות‬
‫לראשונה בכיוון אחורה‪(.‬‬
‫‪ .2‬הוכיחו כי ב‪ G-‬יש מעגל פשוט המכיל את ‪ s‬אםם בכל הרצת‬
‫‪ DFS‬מ‪ s-‬מקבלים לפחות קשת אחת אחורה שנכנסת ל‪.s-‬‬

‫‪9‬‬
‫רכיבים אי פריקים‬

‫הגדרה‪ :‬נתון גרף לא מכוון )‪.G=(V,E‬‬


‫הגדרה‬
‫יהי ∽ יחס שקילות על ‪ ,E‬שמקיים ‪ x ∼ y‬אםם ‪x = y‬‬
‫או שיש מעגל פשוט שמכיל את ‪ x‬ו‪.y-‬‬
‫תתי הגרף הנפרשים על ידי מחלקות השקילות של ∽‬
‫נקראים הרכיבים האי‪-‬פריקים של ‪.G‬‬

‫שימו לב‪ :‬הרכיבים האי‪-‬פריקים זרים בקשתות‪ ,‬אבל לא‬


‫בהכרח זרים בצמתים‪.‬‬

‫הקלט‪ :‬גרף לא מכוון ‪G‬‬


‫הקלט‬

‫הפלט‪ :‬חלוקה של ‪ G‬לרכיבים אי פריקים‪.‬‬


‫הפלט‬

‫‪10‬‬
‫תכונות‬

‫הגדרה‪ :‬צומת ‪ x ∈ V‬נקרא צומת הפרדה אםם‬


‫הגדרה‬
‫הסרתו מגדילה את מספר הרכיבים הקשירים של‬
‫הגרף‪ .‬קשת ‪ e ∈ E‬נקראת גשר אםם הסרתה‬
‫מגדילה את מספר הרכיבים הקשירים של הגרף‪.‬‬
‫גשר ≡ רכיב אי‪-‬פריק עם קשת אחת‪.‬‬
‫צומת הפרדה ≡ חיתוך בין שני רכיבים אי‪-‬פריקים לא‬
‫זרים‪.‬‬

‫)‪ bc(G‬את הגרף שצמתיו הרכיבים‬


‫יהי ‪ G‬גרף‪ .‬נסמן ב‪bc(G)-‬‬
‫האי‪-‬פריקים של ‪ G‬וצמתי ההפרדה של ‪ G‬וקשתותיו‬
‫מחברות בין כל הזוגות של רכיב אי‪-‬פריק וצומת הפרדה‬
‫שמוכל בו‪ .‬אזי )‪ bc(G‬הוא עץ‪.‬‬

‫‪11‬‬
‫צומת הפרדה‬ ‫הדגמה‬
‫גשר‬

‫‪12‬‬
‫צומת הפרדה‬ ‫הדגמה‬
‫גשר‬

‫‪12‬‬
‫צומת הפרדה‬ ‫הדגמה‬
‫גשר‬

‫‪12‬‬
‫הדגמה‬

‫‪13‬‬
‫זיהוי צמתי הפרדה‬

‫נריץ סריקה לעומק של גרף קשיר ‪ G‬החל מצומת ‪ s‬כלשהו‪ .‬נתבונן‬


‫בעץ המכוון ‪.TDFS‬‬
‫משפט‪:‬‬
‫משפט‬
‫השורש ‪ s‬הוא צומת הפרדה אםם יש לו לפחות שני ילדים‪.‬‬
‫כל צומת אחר ‪ x‬הוא צומת הפרדה אםם יש לו ילד ‪ y‬כך שבתת‪-‬‬
‫העץ המושרש ב‪ y-‬אין אף צומת שממנו קשת אחורה לאב‪-‬קדמון‬
‫של ‪.x‬‬

‫‪14‬‬
‫הוכחה‬

‫אם ל‪ s-‬ילד יחיד ‪ ,x‬אזי הסרת ‪ s‬מותירה את תת‪-‬העץ המושרש‬


‫ב‪ .x-‬זהו תת‪-‬גרף קשיר של ‪ ,G‬לכן ‪ s‬אינו צומת הפרדה‪ .‬אם ל‪s-‬‬
‫לפחות שני ילדים ‪ x‬ו‪ ,y-‬אזי הסרת ‪ s‬מותירה לפחות שני תתי‪-‬‬
‫עצים המושרשים ב‪ x-‬וב‪ .y-‬נניח שיש קשת בין צומת ‪ u‬בתת‪-‬עץ‬
‫אחד לצומת ‪ v‬בתת‪-‬העץ האחר‪ .‬בה”כ ‪ u‬נתגלה לפני‬
‫‪) v‬כלומר‪ .(pre[u] < pre[v] ,‬אזי בסריקה מ‪ u-‬חייבים להגיע ל‪,v-‬‬
‫ולכן ‪ v‬באותו תת‪-‬העץ כמו ‪ ,u‬וזו סתירה להנחת קיום הקשת‪.‬‬
‫כלומר‪ ,‬תתי‪-‬העצים הללו הם רכיבים קשירים נבדלים‪ ,‬ולכן ‪ s‬צומת‬
‫הפרדה‪.‬‬

‫‪15‬‬
‫הוכחה )המשך(‬

‫יהי ‪ x‬צומת שאיננו ‪ .s‬אם יש ל‪ x-‬ילד ‪ y‬שבתת‪-‬העץ המושרש בו‬


‫אין אף צומת עם קשת אחורה לאב קדמון של ‪ ,x‬אזי הסרת ‪x‬‬
‫מנתקת את תת‪-‬העץ המושרש ב‪ y-‬משאר הגרף‪ :‬על פי הנתון אין‬
‫אף קשת מתת‪-‬העץ לצומת במסלול מ‪ s-‬ל‪ .x-‬בדומה לטיעון‬
‫הקודם‪ ,‬גם אין קשת מתת‪-‬העץ המושרש ב‪ y-‬לאיזשהו תת‪-‬עץ‬
‫שאינו מכיל את ‪” .y‬שאר הגרף“ כולל לפחות צומת אחד‪ ,s ,‬ולכן ‪x‬‬
‫צומת הפרדה‪.‬‬
‫אחרת‪ ,‬גם אחרי הסרת ‪ x‬כל תת‪-‬עץ שמושרש בילד של ‪ x‬נותר‬
‫ברכיב הקשיר של ‪ .s‬בוודאי כל הצמתים שאינם בתת‪-‬העץ‬
‫המושרש ב‪ x-‬נותרים ברכיב הקשיר של ‪ .s‬לכן מספר הרכיבים‬
‫הקשירים לא עולה‪ ,‬ולכן ‪ x‬איננו צומת הפרדה‪.‬‬

‫‪16‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫הדגמה‬

‫‪s‬‬ ‫‪6‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪17‬‬
‫מציאת צמתי הפרדה‬

‫נחשב לכל צומת ‪ x‬ערך ]‪ ,low[x‬שהוא המינימום של ]‪ pre[z‬על כל‬


‫‪ z‬שניתן להגיע אליו מתת‪-‬העץ המושרש ב‪ x-‬תוך שימוש בקשת‬
‫אחורה אחת לכל היותר‪.‬‬
‫צומת ‪ x‬שאיננו ‪ s‬הוא צומת הפרדה אםם יש ל‪ x-‬ילד ‪ y‬עבורו‬
‫מתקיים ]‪.low[y] ≥ pre[x‬‬
‫לכל צומת ‪ x‬נחזיק ערך ]‪ ,art[x‬שיאותחל ל‪ “no”-‬וישונה ל‪“yes”-‬‬
‫אםם נזהה את ‪ x‬כצומת הפרדה‪.‬‬
‫הערה‪ :‬קשת }‪ {x,y‬היא גשר אםם היא קשת עץ )‪) (x,y‬בחרנו כיוון‬
‫בה”כ(‪ ,‬ו‪.low[y] > pre[x]-‬‬

‫‪18‬‬
‫הדגמה‬

‫בכחול‪ :‬ערך ‪low‬‬


‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬

‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬

‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬


‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬

‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬


‫‪2‬‬ ‫‪1‬‬

‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬

‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬


‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬

‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬


‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪8‬‬ ‫‪9‬‬
‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪8‬‬ ‫‪9 1‬‬


‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪7‬‬
‫‪2‬‬ ‫‪10‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪8‬‬ ‫‪9 1‬‬


‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪7‬‬
‫‪2‬‬ ‫‪10‬‬ ‫‪9‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪8‬‬ ‫‪9 1‬‬


‫‪8‬‬

‫‪19‬‬
‫הדגמה‬
‫‪0‬‬ ‫‪0‬‬ ‫בכחול‪ :‬ערך ‪low‬‬
‫‪0‬‬ ‫‪6‬‬
‫והקשת שקבעה‪.‬‬
‫‪0‬‬ ‫‪9‬‬
‫‪2‬‬ ‫‪0‬‬ ‫‪5‬‬ ‫‪12‬‬
‫‪2‬‬ ‫‪1‬‬
‫‪7‬‬
‫‪2‬‬ ‫‪10‬‬ ‫‪9‬‬
‫‪2‬‬
‫‪3‬‬ ‫‪1‬‬ ‫‪11‬‬
‫‪4‬‬
‫‪7‬‬

‫‪8‬‬ ‫‪9 1‬‬


‫‪8‬‬

‫‪19‬‬
‫ עבור צומת שאיננו השורש‬low ‫חישוב‬
x ‫ ילד של‬y ‫במקרה זה‬
DFS_low(G,x)
low[x] ← pre[x] ← pre_c++
‫ יש‬y-‫העץ המושרש ב‬-‫מתת‬
for each y ∈ Adj[x] do
‫קשת אחורה לאב קדמון‬
if pre[y] = ∞ then ‫ הנוכחי‬low[x] ‫של‬
DFS_low(G,y)
if low[y] < low[x] then low[x] ← low[y]
if low[y] ≥ pre[x] then art[x] ← “yes”
else if pre[y] < low[x] then
low[x] ← pre[y] x ‫ אב קדמון של‬y ‫במקרה זה‬
end if
end for
end DFS_low

20
‫סימון הרכיבים האי‪-‬פריקים‬
‫‪for each y ∈ Adj[x] do‬‬
‫)‪ then push({x,y},stack‬לא סרקנו עדיין את }‪if {x,y‬‬
‫‪if pre[y] = ∞ then‬‬
‫‪...‬‬ ‫נחזיק מחסנית של קשתות‬
‫‪if low[y] ≥ pre[x] then‬‬
‫”‪art[x] ← “yes‬‬ ‫זה מונה של מספר הרכיבים‬
‫‪bcc_c++‬‬
‫‪repeat‬‬ ‫את הלולאה של שליפת קשתות‬
‫)‪e ← pop(stack‬‬ ‫מהמחסנית צריך לבצע גם עבור‬
‫‪bcc[e] ← bcc_c‬‬ ‫כל ילד ‪ y‬של השורש ‪.s‬‬
‫}‪while e ≠ {x,y‬‬
‫‪end if‬‬
‫‪...‬‬ ‫שימו לב‪ :‬ייתכן של‪ x-‬יש מספר ילדים‬
‫‪end if‬‬ ‫שיזהו אותו כצומת הפרדה‪ ,‬ואז כל ילד‬
‫‪end for‬‬ ‫כזה יגרום לשליפת רכיב אי‪-‬פריק‪.‬‬
‫‪21‬‬
‫סיבוכיות‬

‫הסריקה לעומק לוקחת )|‪ O(|V|+|E‬זמן‪.‬‬


‫השינויים לחישוב ‪ low‬לא משנים את הסיבוכיות‪.‬‬
‫לכל קשת מבצעים )‪ O(1‬פעולות מחסנית‪.‬‬
‫סה”כ סיבוכיות הזמן‪O(|V|+|E|) :‬‬
‫סיבוכיות המקום‪O(|V|+|E|) :‬‬

‫‪22‬‬
‫תרגיל בית‬

‫הוכיחו שבכל פעם שמבצעים את לולאת ‪ repeat‬אכן‬


‫קבוצת הקשתות הנשלפת מהמחסנית היא רכיב אי‪-‬‬
‫פריק‪.‬‬

‫‪23‬‬
‫רכיבים קשירים היטב‬

‫הגדרה‪ :‬נתון גרף מכוון )‪.G=(V,E‬‬


‫הגדרה‬
‫יהי ∽ יחס שקילות על ‪ ,V‬שמקיים ‪ x ∼ y‬אםם יש‬
‫מסלול מכוון מ‪ x-‬ל‪ y-‬וגם מ‪ y-‬ל‪.x-‬‬
‫תתי הגרף הנפרשים על ידי מחלקות השקילות של ∽‬
‫נקראים הרכיבים הקשירים היטב של ‪.G‬‬

‫שימו לב‪ :‬תיתכנה קשתות של ‪ G‬שאין כלולות בשום‬


‫רכיב קשיר היטב‪.‬‬

‫הקלט‪ :‬גרף מכוון ‪.G‬‬


‫הקלט‬

‫הפלט‪ :‬חלוקה של ‪ G‬לרכיבים קשירים היטב‪.‬‬


‫הפלט‬

‫‪24‬‬
‫הדגמה‬

‫‪25‬‬
‫הדגמה‬

‫‪25‬‬
Kosaraju-Sharir ‫אלגוריתם‬
KS(G)
for each x ∈ V do post[x]←∞, from[x]←nil, scc[x]←∞
post_c ← 0, scc_c ← 0
for each x ∈ V do ‫ יציין את‬scc[x] ‫הערך‬
if post[x] = ∞ then DFS(G,x) .x ‫מספר הרכיב אליו שייך‬
end for
sort(V,-post) ‫ יורד‬post ‫ בסדר‬V ‫נמיין את‬
for each x ∈ V do
if scc[x] = ∞ then
DFS_scc(GT,x)
scc_c++ ‫ על‬G-‫מתקבל מ‬GT ‫הגרף‬
end if .‫ידי הפיכת כל הקשתות‬
end for
end KS
26
‫קשתות עץ‬ ‫הדגמה‪ :‬תוצאות ‪DFS‬‬
‫קשתות קדימה‬
‫קשתות אחורה‬
‫קשתות הצידה‬
‫‪2‬‬ ‫‪2, 3‬‬
‫‪1, 6‬‬
‫‪7‬‬ ‫‪3‬‬
‫‪1‬‬ ‫‪8‬‬
‫‪3, 2‬‬
‫‪0, 7‬‬ ‫‪9‬‬
‫‪12‬‬ ‫‪6‬‬
‫‪6, 5‬‬ ‫‪4‬‬
‫‪5, 0‬‬
‫‪11‬‬ ‫‪5‬‬
‫‪10‬‬ ‫‪4, 1‬‬
‫המספרים על הקשתות‪:‬‬
‫סדר הסריקה‪.‬‬
‫‪7, 4‬‬
‫זוגות המספרים על הצמתים‪:‬‬
‫סדר הגילוי וסדר החזרה‪.‬‬
‫‪27‬‬
‫איסוף רכיב קשיר היטב‬

DFS_scc(G,x)
scc[x] ← scc_c
for each y ∈ Adj[x] do
if scc[y] = ∞ then DFS_scc(G,y)
end for
end DFS_scc

28
‫קשתות עץ‬ ‫הדגמה‪ :‬תוצאות ‪DFS_scc‬‬
‫קשתות קדימה‬
‫קשתות אחורה‬
‫קשתות הצידה‬ ‫‪3‬‬
‫‪63, 0‬‬ ‫‪6‬‬ ‫‪4, 4‬‬

‫‪12‬‬ ‫‪7‬‬
‫‪5‬‬ ‫‪2‬‬
‫‪7‬‬ ‫‪4‬‬ ‫‪5, 7‬‬
‫‪0, 3‬‬ ‫‪11‬‬
‫‪3‬‬ ‫‪5‬‬ ‫‪8‬‬
‫‪2, 1‬‬ ‫‪10‬‬ ‫‪0‬‬
‫‪6, 6‬‬
‫‪1‬‬ ‫‪1‬‬ ‫‪9‬‬
‫‪2‬‬ ‫‪7, 5‬‬
‫המספרים על הקשתות‪:‬‬
‫סדר הסריקה‪.‬‬
‫‪1, 2 4‬‬
‫באדום‪ :‬סדר‬ ‫זוגות המספרים על הצמתים‪:‬‬
‫החזרה ב‪DFS-‬‬ ‫סדר הגילוי וסדר החזרה‪.‬‬
‫‪29‬‬
‫הוכחת נכונות‬

‫נתבונן בלולאה של הרצת ‪ DFS‬על ‪.G‬‬


‫אבחנה‪ :‬הגרף הנפרש על ידי קשתות העץ הוא אוסף של עצים‬‫אבחנה‬
‫מכוונים זרים הפורשים יחד את )‪) .V(G‬כל קריאה מהפרוצדורה‬
‫‪ KS‬ל‪ DFS(G,x)-‬מייצרת עץ מושרש ב‪(.x-‬‬
‫הגדרה‪ :‬לכל ‪ x ∈ V‬נסמן ב‪ φ(x)-‬את הצומת בעל ערך ‪post‬‬
‫הגדרה‬
‫המירבי מבין כל הצמתים הנגישים מ‪ x-‬ב‪.G-‬‬
‫לב‪) φ(φ(x)) = φ(x) :‬מדוע?(‬
‫שימו לב‬
‫טענה‬
‫טענה‪ :‬ב‪ G-‬יש מסלול מכוון מ‪ φ(x)-‬ל‪ x-‬ולכן ‪ x‬ו‪ φ(x)-‬באותו רכיב‬
‫קשיר היטב‪.‬‬

‫‪30‬‬
‫קשתות עץ‬ ‫הדגמה‪ :‬חישוב ‪φ‬‬
‫קשתות קדימה‬
‫קשתות אחורה‬
‫קשתות הצידה‬
‫‪3, 3‬‬
‫‪6, 7‬‬

‫‪2, 2‬‬
‫‪7, 7‬‬
‫‪5, 7‬‬
‫‪0, 2‬‬
‫‪1, 2‬‬

‫‪4, 7‬‬
‫זוגות המספרים על הצמתים‪:‬‬
‫סדר החזרה וערך ‪.φ‬‬
‫‪31‬‬
‫הוכחת נכונות )המשך(‬

‫הוכחה‪ :‬אם ‪ φ(x) = x‬אז בוודאי הטענה נכונה‪ .‬אם חזרנו כבר‬
‫הוכחה‬
‫מ‪ φ(x)-‬לפני שגילינו את ‪ x‬אז ]‪ ,post[φ(x)] < post[x‬וזו סתירה‬
‫להגדרת )‪.φ(x‬‬
‫נניח שגילינו את ‪ x‬לפני שגילינו את )‪ .φ(x‬אזי יהי ‪ z‬הצומת‬
‫האחרון במסלול מ‪ x-‬ל‪ φ(x)-‬שנתגלה לפני או בזמן גילוי ‪ .x‬יש‬
‫כזה כי ‪ x‬כזה‪ .‬כל הצמתים בקטע המסלול מ‪ z-‬ל‪ φ(x)-‬עדיין לא‬
‫נתגלו בזמן גילוי ‪ .z‬לכן כולם‪ ,‬בפרט )‪ φ(x‬יתגלו בין גילוי ‪ z‬לחזרה‬
‫מ‪ .z-‬לכן ]‪ post[φ(x)] < post[z‬וזו סתירה להגדרה של )‪ ,φ(x‬כי ‪z‬‬
‫נגיש מ‪.x-‬‬
‫לכן‪ ,‬האפשרות היחידה היא ש‪ x-‬נתגלה בין גילוי )‪ φ(x‬לבין‬
‫החזרה מ‪ ,φ(x)-‬כלומר‪ x ,‬נמצא בתת‪-‬העץ המושרש ב‪ ,φ(x)-‬ולכן‬
‫יש מסלול מכוון מ‪ φ(x)-‬ל‪∴ .x-‬‬

‫‪32‬‬
‫הוכחת נכונות )המשך(‬

‫מסקנה‪ :‬שני צמתים ‪ x,y‬נמצאים באותו רכיב קשיר היטב‬


‫מסקנה‬
‫אםם )‪.φ(x) = φ(y‬‬
‫הוכחה‪ :‬כל הצמתים באותו רכיב נגישים זה מזה‪ ,‬ולכן לכולם אותו‬
‫הוכחה‬
‫ערך ‪ .φ‬מצד שני‪ x ,‬ו‪ φ(x)-‬באותו רכיב וכך גם ‪ y‬ו‪ .φ(y)-‬לכן‪,‬‬
‫אם )‪ ,φ(x) = φ(y‬אז ‪ x,y‬באותו רכיב‪.‬‬

‫‪33‬‬
‫הוכחת נכונות )המשך(‬

‫עכשיו נתבונן בקריאה ל‪DFS_scc(GT,x)-‬‬


‫הקריאות הקודמות )אם היו( ל‪ DFS_scc-‬לא גילו את ‪ ,x‬ולכן ב‪GT-‬‬
‫אין אף מסלול מצומת שנתגלה בקריאות הקודמות ל‪ ,x-‬כלומר ב‪-‬‬
‫‪ G‬אין אף מסלול מ‪ x-‬לצומת שנתגלה בקריאות הקודמות‪ .‬אבל‪,‬‬
‫קבוצת הצמתים שנתגלתה בקריאות הללו כוללת את כל הצמתים‬
‫עם ערך ‪ post‬מ‪ DFS-‬הגדול מ‪ post[x]-‬ולכן ‪.φ(x) = x‬‬
‫הצמתים המתגלים בקריאה ל‪ DFS_scc(GT,x)-‬הם בדיוק‬
‫הצמתים שנגישים ב‪ GT-‬מ‪ .x-‬לכל צומת כזה ‪ y‬יש ב‪ G-‬מסלול מ‪-‬‬
‫‪ y‬ל‪ .x-‬אבל ‪ x‬בעל ערך ‪ post‬המירבי מבין כל הצמתים שנותרו‪,‬‬
‫כך ש‪ .φ(y) = x-‬כלומר‪ ,‬הקריאה ל‪ DFS_scc(GT,x)-‬מסמנת את‬
‫הרכיב הקשיר היטב של ‪∴ .x‬‬

‫‪34‬‬

You might also like