שיעור במבני נתונים ויעילות אלגוריתמים מיום ד` (7.1)
Download
Report
Transcript שיעור במבני נתונים ויעילות אלגוריתמים מיום ד` (7.1)
מכללת אורט כפר-סבא
מבני נתונים
ויעילות אלגוריתמים
מבוא לתורת הגרפים
07.01.15
אורי וולטמן
[email protected]
חידה לחימום
אמיר ומיכל משחקים במשחק .על לוח המשחק מונחים 1,000מטבעות
בשורה .לכל מטבע בשורה יש ערך שהוא מספר חיובי והשחקנים יודעים
בתחילת המשחק את ערכיהם של כל המטבעות.
המשחק מתנהל בתורות ,לסירוגין .בכל תור ,השחקן שמשחק בוחר מטבע
מאחד משני קצוות השורה ולוקח אותו לקופה שלו .לאחר 1,000תורות
נגמרים המטבעות בשורה .בשלב זה ,סופרים את סכום ערכי המטבעות
שבקופה של כל אחד מהשחקנים .השחקן שצבר סכום גדול יותר ,מנצח
במשחק .במקרה של שוויון בסכומים ,המשחק מוכרז כתיקו.
אמיר משחק ראשון .הוא ממש לא רוצה להפסיד .לא אכפת לו אם המשחק
יסתיים בתיקו או בניצחון שלו .מצאו אסטרטגיה עבור אמיר שתבטיח שהוא
לא יפסיד במשחק.
הגדרות יסודיות
תורת הגרפים ( )Graph Theoryהיא ענף חשוב במתמטיקה ,ולו
יישומים רבים בתחומי מדע שונים .גם במדעי המחשב משתמשים
בגרפים ,בתור טיפוס נתונים עליו ניתן להפעיל אלגוריתמים שימושיים.
אבל מה זה בעצם 'גרף'?
אנחנו נגדיר גרף ( )graphבתור אוסף של צמתים או קודקודים (באנגלית
,verticesוביחיד – ,)vertex
אשר ביניהם יש קשתות או צלעות (באנגלית .)edges
נסמן את קבוצת הקודקודים באות ,Vואת קבוצת הצלעות באות .E
בדרך-כלל מכנים גרפים בשמות (כגון ,)Gוכותבים זאת כך.G = (V,E) :
הנה ,למשל ,מספר גרפים:
דרגה של קודקוד
זוג קודקודים הנמצאים משני צידיה של קשת נקראים סמוכים ( )adjacentאו
שכנים .נעיין בגרף הבא ,אשר קודקודיו מסומנים באותיות:
בגרף זה ,שכניו של הקודקוד xהם uו .v-השכן
היחידי של הקודקוד yהוא הקודקוד .uהקודקוד
wהוא קודקוד מבודד ,ללא שכנים.
לקודקוד vיש קשת היוצאת ממנו ונכנסת אליו
חזרה .קשת כזו מכונה לולאה עצמית
( ,)self loopאו בקיצור – לולאה (.)loop
הגדרה :נגדיר דרגה ( )degreeשל קודקוד vבתור מספר הקשתות הנוגעות
בו ,ונסמן זאת ).d(v
למשל ,עבור הגרף הזה מתקיים:
d(x) = 2
d(u) = 3
d(y) = 1
d(w) = 0
d(v) = 4
ניתן לראות שדרגתו של קודקוד מבודד היא
אפס (כי אין אף קשת שנוגעת בו).
כמו כן ,עבור הקודקוד ,vרואים כי הלולאה
"תורמת" 2לדרגת הקודקוד (פעם כשהקשת
יוצאת מהקודקוד ,ופעם שהקשת נכנסת).
דרגה של קודקוד
טענה :בכל גרף ,סכום דרגות כל הקודקודים שווה לפעמיים מספר
הקשתות:
d ( x) 2 E
xV
טענה זו מכונה לעיתים 'משפט לחיצת
הידיים':
נדמיין קבוצת אנשים שחלקם לוחצים ידיים האחד עם השני ,ונייצג
קבוצה זו על-ידי גרף.
כל אדם ייוצג על-ידי קודקוד ,ונמתח קשת בין שני קודקודים אם שני
האנשים לחצו ידיים.
נניח שכל אדם זוכר לכמה אנשים אחרים הוא לחץ ידיים (זוהי דרגת
הקודקוד).
משמעות המשפט היא שאם נבקש מכל אדם לומר את מספר האנשים
איתם הוא לחץ ידיים ,ונסכם את כל המספרים ,נקבל מספר הגדול פי 2
ממספר לחיצות הידיים שהתבצעו.
דרגה של קודקוד
טענה :בכל גרף ,סכום דרגות כל הקודקודים שווה לפעמיים מספר
הקשתות:
d ( x) 2 E
xV
האם קיים גרף בעל 7קודקודים ,שדרגתו של כל אחד מהם היא ?5
האם קיים גרף שסדרת דרגותיו היא...
.5 ,4 ,3 ,2 ,2 ,1
.3 ,2 ,1 ,1 ,1 ,1 ,1 ,0 ,0
.5 ,5 ,4 ,4 ,0
.5 ,4 ,3 ,3 ,2 ,2
דרגה של קודקוד
סדרת מספרים שלמים אי-שליליים עבורה קיים גרף שזוהי סדרת דרגות
קודקודיו ,נקראת סדרה גראפית (.)graphic sequence
כפי שראינו ,לא כל סדרה היא גראפית ,וקיימות סדרות של מספרים
שאינן מייצגות דרגות קודקודים של גרף.
קיימים אלגוריתמים (כגון אלגוריתם )Havel-Hakimiהמקבלים סדרה
גראפית ,ובונים ממנה גרף.
שאלה :הוכיחו כי אם בגרף יש nקודקודים ו n+4 -קשתות ,וכל הדרגות
הן לפחות ,3אזי . n < 8
גרף פשוט
ישנם גרפים אשר בהם יש יותר מקשת אחת בין שני קודקודים .קשתות כאלה
נקראות קשתות מקבילות או קשתות מרובות ( .)multiple edgesהגרף הבא
הוא דוגמא לגרף אשר יש בו קשתות מקבילות:
גרף שאיננו מכיל קשתות מקבילות וגם לא לולאות
עצמיות ,נקרא גרף פשוט (.)simple graph
רוב הגרפים בהם נעסוק יהיו פשוטים .כל הגרפים שראינו עד כה ,למעט זה
שקודקודיו סומנו באותיות ,היו גרפים פשוטים.
לפניכם שלושה גרפים .קבעו לגבי כל אחד האם הוא פשוט או לא:
גרף מכוון
לעיתים ,נרצה לתת לקשתות הגרף כיוון (למשל ,אם אנחנו משתמשים בגרף
על מנת לייצג רשת של כבישים ,וחלק מהכבישים הם חד-סיטריים).
לגרף שבו הקשתות הן מכוונות נקרא גרף מכוון ( ,directed graphאו בקיצור
.)digraphגרף שבו הקשתות אינן מכוונות (וכל הגרפים בהם נתקלנו עד כה
היו כאלו) נקרא גרף לא-מכוון ( .)non-directed graphדוגמא לגרף מכוון:
אם ניקח גרף מכוון ,ונתעלם מהכיוונים על הקשתות,
נקבל גרף לא-מכוון הנקרא גרף התשתית שלו.
בגרף מכוון ,נגדיר לכל צומת את דרגת הכניסה ()in-degree
ודרגת היציאה ( )out-degreeבתור מספר הקשתות
המכוונות הנכנסות והיוצאות מתוך הצומת ,בהתאמה.
נסמן ב din(x)-את דרגת הכניסה של צומת ,xואת דרגת היציאה שלו .dout(x) -
ברור שדרגה של כל צומת (בגרף התשתית הלא-מכוון) שווה לסכום דרגת
הכניסה ודרגת היציאה.din(x) + dout(x) = d(x) :
בגרף מכוון פשוט מותר שיהיו שתי קשתות המחברות בין שני קודקודים ,בתנאי
שכיווניהן הפוכים .קשתות כאלה נקראות קשתות אנטי-מקבילות.
נסחו גירסה של משפט לחיצות הידיים עבור גרפים מכוונים.
גרף ממושקל
לעיתים נרצה להצמיד לכל קשת מספר הנקרא המשקל ( )weightשל הקשת.
המשקל של קשת יכול לייצג דברים שונים .אם ,למשל ,הגרף מייצג מערכת
כבישים (כל קודקוד מייצג עיר ,וכל קשת מייצגת כביש המחבר שני ערים) ,אז
המשקל של קשת יכול לציין ,לדוגמא:
את המרחק בקילומטרים שבין עיר לעיר.
את מהירות הנסיעה המקסימלית בקמ"ש בכביש הזה.
את המחיר שצריך לשלם בשקלים עבור הנסיעה בכביש (אם מדובר בכביש אגרה) ,וכו'.
גרף שבו לכל קשת מוצמד משקל ,נקרא גרף ממושקל (.)weighted graph
כל הגרפים בהם נתקלנו עד כה היו גרפים לא-ממושקלים ( un-weighted
.)graphs
להלן דוגמא לשני גרפים ממושקלים,
האחד מהם מכוון והשני לא-מכוון:
משקל של קשת אינו בהכרח מספר
טבעי .ייתכנו קשתות שמשקליהן הם
שברים ,מס' שליליים ,אפס ,וכו'.
שאלה
עד כה הכרנו מספר תכונות לגבי גרפים .ראינו כי גרף יכול להיות...
פשוט /לא פשוט
מכוון /לא מכוון
ממושקל /לא ממושקל
שרטטו דוגמא לגרף אחד מכל אחד מהצירופים האפשריים של שלושת
התכונות (לדוגמא :גרף פשוט לא-מכוון וממושקל ,גרף לא-פשוט לא-
מכוון ולא-ממושקל ,וכו').
כמה צירופים כאלו יש?
שאלה
משפחה מפורסמת של גרפים נקראת הגרפים השלמים (,)complete graphs
והיא מסומנת .Knהגרף השלם על nקודקודים ,עבור nשלם וחיובי (טבעי),
הוא גרף פשוט שבו כל שני קודקודים הם סמוכים.
לדוגמא ,הגרפים K2, K3, K4יראו כך:
שרטטו את K5ואת .K6
איך יראה ?K1
ספרו את מספר הקשתות עבור כל אחד מהגרפים , Kiעבור .i = 1..6
האם תוכלו לתת נוסחא כללית עבור מספר הקשתות של הגרף Knולהסביר
מדוע היא נכונה?
נסו להוכיח את טענתכם בשתי דרכים :ע"י בניית נוסחת נסיגה ופתירתה ,וע"י שימוש
במשפט לחיצת הידיים.
מסלולים
נכנה בשם מסלול ( )pathכל סדרה של קשתות המחברות קודקודים סמוכים.
אורך של מסלול פירושו מספר הקשתות שבו.
מסלול שבו הקודקוד הראשון והאחרון הם אותו הקודקוד ,נקרא מעגל (.)cycle
לדוגמא AEBA :הוא מעגל באורך .3
מסלול יקרא פשוט ( )simple pathאם אף קודקוד לא חוזר בו יותר מפעם
אחת ,ומעגל יקרא פשוט ( )simple cycleאם אף קודקוד ,פרט לקודקוד
הראשון (שהוא גם האחרון) ,לא חוזר בו יותר מפעם אחת ,ואף קשת לא חוזרת
יותר מפעם אחת.
לדוגמא AEBD :הוא מסלול באורך .3
CABמסלול באורך .2
בכל הדוגמאות שראינו לעיל הופיעו מסלולים פשוטים
ומעגלים פשוטים.
המסלול AEBDBEהוא מסלול לא פשוט באורך .5
המעגל BACABהוא מעגל לא פשוט באורך .4
האם בהגדרה ניתן לוותר על החלק "ואף קשת?"...
גרף לא-מכוון ייקרא קשיר ( )connectedאם מכל קודקוד
ניתן להגיע לכל קודקוד אחר על-ידי מסלול.
גרף קשיר
כאמור ,גרף לא-מכוון ייקרא קשיר ( )connectedאם מכל קודקוד ניתן להגיע
לכל קודקוד אחר על-ידי מסלול.
נביט בגרף הלא-קשיר הבא:
בגרף לא-מכוון ,רכיב קשירות ( )connected componentהוא תת-גרף קשיר
של הגרף המקורי הכולל את כל הקודקודים שניתן להגיע אליהם מקודקוד נתון.
לדוגמא ,בגרף הנתון ישנם שלושה רכיבי קשירות:
רכיב קשירות אחד כולל את הקודקודים .1,2,3,4,8
רכיב קשירות אחר כולל את הקודקודים .0,5,6
רכיב קשירות נוסף כולל את הקודקוד .7
קודקוד כזה ,שדרגתו היא אפס ,נקרא קודקוד מבודד ( .)isolated vertexקודקוד מבודד
הוא קודקוד הנמצא לבדו ברכיב קשירות.
בגרף קשיר יש בדיוק רכיב קשירות אחד.
גרף קשיר בחוזקה
גרף מכוון ייקרא קשיר היטב או קשיר בחוזקה ( )strongly connectedאם
מכל קודקוד ניתן להגיע לכל קודקוד אחר על-ידי מסלול מכוון.
לדוגמא ,הגרף G1הוא קשיר בחוזקה ,ואילו הגרף G2אינו קשיר בחוזקה:
2
G
1
G
בגרף מכוון ,רכיב קשירות בחוזקה (,)strongly connected component
המכונה בקיצור רק"ח ( ,)SCCהוא תת-גרף קשיר-בחוזקה של הגרף המקורי
הכולל את כל הקודקודים שניתן להגיע אליהם מקודקוד נתון.
בגרף קשיר בחוזקה יש בדיוק רכיב קשירות בחוזקה (רק"ח) אחד.
מטריצת סמיכויות
אחת הדרכים הנפוצות לייצג גרף בזיכרון המחשב ,היא באמצעות מטריצת
סמיכויות ( ,)adjacency matrixהנקראת גם מטריצת שכנויות.
שיטה זו היא אפקטיבית בעיקר כאשר ידוע מראש המס' המקסימלי של
קודקודים בגרף.
נסמן מס' זה ב ,n-ונניח שלכל קודקוד יוצמד מספר בין 0לבין .n-1
כעת ,נגדיר מטריצה ריבועית Aבגודל .nxn
אם קיימת קשת בין קודקוד iלבין קודקוד ,jאז נציב את הערך ( 1או את
הערך הבוליאני )TRUEבתא ] .A[i][jאם לא קיימת קשת כזו ,אז נציב בתא
זה את הערך ( 0או את הערך הבוליאני .)FALSE
לדוגמא:
נשים לב שמטריצת הסמיכויות היא
מטריצה סימטרית .מדוע זה כך?
מטריצת סמיכויות
כיצד ניתן לחשב ,באמצעות מטריצת סמיכויות ,את הדרגה ( )degreeשל קודקוד?
באמצעות ספירת מספר ה-1-ים בשורה המתאימה לו ,או בעמודה המתאימה לו.
מהי סיבוכיות זמן הריצה של חישוב זה?
)Ө(n
כיצד ניתן לגלות ,באמצעות מטריצת סמיכויות ,האם יש בגרף לולאה עצמית?
נבדוק האם המספר 1מופיע על האלכסון הראשי של המטריצה.
שימו לב שבמקרה כזה ,כדי לחשב את דרגת הקודקוד יש לספור את האלכסון הראשי פעמיים.
כיצד ניתן לזהות ,באמצעות מטריצת סמיכויות ,קודקוד מבודד?
בשורה/בעמודה המתאימה לקודקוד ,מופיעים רק אפסים (פרט לאלכסון הראשי).
כיצד תיראה מטריצת הסמיכויות של גרף שלם ?Kn
כל הערכים במטריצה יהיו -1ים ,פרט לאלכסון הראשי שיכיל רק -0ים.
מה תהיה סיבוכיות זמן הריצה של אלגוריתם ,הבודק האם
הגרף אוילריאני?
)Ө(n2
מטריצת סמיכויות
ראינו כיצד ניתן לייצג באמצעות מטריצת סמיכויות גרף בלתי מכוון .אולם
האם תעבוד שיטה זו גם עבור גרף מכוון?
נשים 1בתא ] A[i][jאם יש קשת מכוונת היוצאת מ i-ונכנסת ל.j-
בשיטה זו ,מטריצת הסמיכויות לא תהיה בהכרח סימטרית ,משום שמקיומה של קשת
מכוונת מקודקוד iלקודקוד jלא ניתן להסיק שקיימת קשת מכוונת מקודקוד jלקודקוד .i
מה מאפיין גרף מכוון שמטריצת הסמיכויות שלו היא סימטרית?
בצד כל קשת מכוונת המופיעה בו ,מופיעה גם קשת אנטי-מקבילה.
כיצד ניתן לחשב את דרגת היציאה ( )out-degreeשל קודקוד?
לספור את כמות ה-1-ים בשורה המתאימה לקודקוד.
כיצד ניתן לחשב את דרגת הכניסה ( )in-degreeשל קודקוד?
לספור את כמות ה-1-ים בעמודה המתאימה לקודקוד.
מטריצת סמיכויות
נניח שרוצים לייצג באמצעות מטריצת סמיכויות גרף ממושקל ( ,)weightedמכוון או
בלתי מכוון.
הנה הצעה :אם לא קיימת קשת בין קודקוד iלבין קודקוד jאז נשים 0בתא ] ,A[i][jואם
קיימת קשת בין שני הקודקודים – אז בתא ] A[i][jנאחסן מספר המציין את משקל
הקשת .איזו חולשה יש בפתרון הזה?
הפתרון הזה יעבוד ,רק בתנאי שאסור שמשקל קשת יהיה שווה לאפס! אם מרשים שמשקל
של קשת יהיה שווה לאפס ,לא נדע להבחין בין מקרה בו בין שני קודקודים לא קיימת קשת
כלל ,לבין מקרה בו קיימת קשת ,אולם המשקל שלה הוא אפס.
אפשרות אחרת ,היא להגדיר מטריצת סמיכויות שכל אחד מהתאים בה מכיל שני
ערכים :דגל בוליאני הקובע האם קיימת קשת או לא ,ומספר המציין את משקל הקשת
(אם קיימת).
לדוגמא:
{ struct edge
;int exists
*/שדה שערכו 1אם קיימת קשת ,ו 0-אם לא */
*/שדה שערכו משקל הקשת ,אם היא קיימת *float weight; /
;}
;]struct edge adjacency_matrix[N][N
מטריצת סמיכויות
לדוגמא ,את הגרף המכוון והממושקל הזה:
נייצג באמצעות מטריצת הסמיכויות הבאה:
מה סיבוכיות זמן הריצה של אלגוריתם
המוצא את משקל הקשת הקלה ביותר?
)Ө(n2
שיטת ייצוג זו אינה תומכת בגרפים עם
קשתות מקבילות (יותר מקשת אחת בין שני
קודקודים) .כיצד ניתן לייצג גרף כזה?
ניתן לשים בכל תא במטריצה מצביע לראש
רשימה מקושרת של מבנים ,כאשר כל
מבנה מייצג קשת ומכיל שדה ובו משקל
הקשת.
רשימת סמיכויות
שיטה נוספת לייצג גרף בזיכרון המחשב ,היא באמצעות רשימת סמיכויות
( ,)adjacency listהנקראת גם רשימת שכנויות.
הרעיון הוא להגדיר מערך (או רשימה מקושרת) שכל אחד מאיבריו ייצג
קודקוד אחד ,ולכל אחד מאיברים אלה – תוצמד רשימה מקושרת של כל
הצמתים שהם שכנים של אותו הקודקוד.
לדוגמא ,הגרף המכוון הזה ,ייוצג כך:
רשימת סמיכויות
כיצד ניתן לייצג גרפים ממושקלים בשיטה זו?
נוסיף לכל חוליה ברשימה המקושרת שדה נוסף ,המייצג את משקל הקשת.
לדוגמא:
אם ידוע שהגרף הוא דליל ( ,)sparseכלומר – שמספר הקשתות בו קטן
מאוד ביחס למספר הקשתות האפשריות ,באיזה ייצוג עדיף להשתמש:
במטריצת סמיכויות או ברשימת סמיכויות?
האם ניתן לייצג באמצעות רשימת סמיכויות גם גרף בלתי מכוון?
תרגיל
נתון גרף ) ,G = (V,Eשהוא פשוט ,בלתי מכוון ובלתי ממושקל:
ייצגו את הגרף Gבאמצעות רשימת סמיכויות.
חשבו את סכום האורכים של כל רשימות הסמיכויות.
מה הקשר בין התוצאה שקיבלתם לבין מספר הקשתות בגרף?
תרגיל
נתון גרף ) ,G = (V,Eשהוא פשוט ,מכוון וממושקל:
ייצגו את הגרף Gבאמצעות מטריצת סמיכויות.
ייצגו את הגרף Gבאמצעות רשימת סמיכויות.
תרגיל
נתון גרף מכוון ) .G = (V,Eנגדיר את הגרף המשוחלף ) GT = (V,ETבאופן הבא:
קבוצת קודקודיו של הגרף המשוחלף היא ,Vכלומר – זהה לקבוצת הקודקודים של הגרף
המקורי.
קבוצת קשתותיו של הגרף המשוחלף היא ,ETהמוגדרת באופן הבא:
כלומר ,קשת ) (u,vשייכת לקבוצת הקשתות ETשל הגרף המשוחלף ,רק אם הקשת
) (v,uשייכת לקבוצת הקשתות Eשל הגרף המקורי.
למשל ,עבור הגרף Gהבא:
הגרף המשוחלף GTהוא:
פתחו אלגוריתם המקבל כקלט את ,Gומחשב את .GTכתבו את האלגוריתם בשתי גירסאות:
במקרה שהגרף מיוצג כמטריצת סמיכויות ובמקרה שהגרף מיוצג כרשימת סמיכויות.
נתחו את סיבוכיות זמן הריצה של שני האלגוריתמים.