מבני נתונים ואלגוריתמים - מחברת קורס/גרפים/גרפים וייצוגיהם/תרגילים

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי


מימוש לפונקציית המעבר על הקשתות[עריכה]

שאלה[עריכה]

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


אנא הסבר כיצד לשנות את המימוש כך שסיבוכיות הפונקציה תרד ל, מבלי להגדיל את סיבוכיות הפונקציות האחרות. אנא הסבר בקצרה (רצוי בתרשים) את השינויים הנדרשים, וכתוב את הפסוודו-קוד לפונקציה E(G).

מותר לך לעשות שינויים מבניים במבנה הנתונים המייצג את הגרף (דהיינו, להוסיף או לשנות שדות, או להוסיף עוד מבני-נתונים פנימיים). עם זאת, נסה לעשות מספר קטן ככל האפשר של שינויים.

תשובה[עריכה]

נוסיף עוד רשימה מקושרת, has-neighbors, המתארת את הצמתים שלהם יש שכנים.



דוגמה:

בתרשים הבא, הרשימה המקושרת has-neighbors מכילה חוליות בעלות התוכן 1, 2, 3, ו4, מפני שאלה הצמתים שלהם שכנים.

שתי הרשימות המקושרות.
שתי הרשימות המקושרות.


קל לראות שסיבוכיות A(G, u) וV(G) אינן מושפעות מהוספת הרשימה המקושרת (הן אינן משתמשות בו). להלן הפסוודו-קוד החדש של E(G):

Count-Num-Edges(G)
1	count = 0
		
2	lnk = G.has-neighbors.front
	
3	while lnk != Nil
4		u = lnk.value
			
5		count = count + Size( G.Vertexes[u] )
	
6		lnk = lnk.next
	
7	return count
	
	
# Returns an array of the edges of a graph (G).
E(G)
1	Edges = Make-Array( Count-Num-Edges(G) )
			
2	i = 0
	
3	lnk = G.has-neighbors.front
		
4	while lnk != Nil
5		u = lnk.value
			
6		for v in A(G, u)		
7			Edges[i++] = (u, v)
	
8		lnk = lnk.next
				
9	return Edges

פונציית-העזר Count-Num-Edges סופרת את מספר הצמתים. שורה 1 מאתחלת משתנה הסופר את מספר הצמתים ל0, ושורה 7 מחזירה אותו. הלולאה 3-6 (יחד עם 2) עוברת על כל חוליות has-neighbors. עבור כל חוליה, 4 מוצאת את מספר הצומת, ו מוצאת את מספר שכניו. הפונקציה E מייצרת את המערך Edges ב1, ומחזירה אותו ב9. הלולאה 4-8 (יחד עם 3) עוברת על כל חוליות has-neighbors. עבור כל חוליה, 5 מוצאת את מספר הצומת, ו רצות על שכניו. לכל שכן, קשת מתאימה מיתוספת לEdges.

חישוב דרגות כניסה ויציאה[עריכה]

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



שאלה[עריכה]

נתון גרף ברשימת שכנויות.

  1. רוצים לחשב, לכל צומת , את דרגת היציאה שלו (כלומר, כמה קשתות יוצאות ממנו). מה הסיבוכיות הנדרשת?
  2. רוצים לחשב, לכל צומת , את דרגת הכניסה שלו (כלומר, כמה קשתות נכנסות אליו). מה הסיבוכיות הנדרשת?




לחיצת ידיים במסיבה[עריכה]

שאלה[עריכה]

במסיבה כלשהי יש אנשים; חלקם לחץ ידיים זה עם זה. אנא הוכח שמספר האנשים שלחצו ידיים עם מספר אי-זוגי של אנשים - הוא זוגי.



דוגמה:

נניח שבמסיבה יש שלשה אנשים: 1,‏ 2,‏ ו3, ורק 1 ו2 לחצו ידיים זה עם זה. יש שני אנשים שלחצו ידיים עם אדם אחד; אכן יש מספר זוגי (שניים) של אנשים שלחצו ידיים עם מספר אי-זוגי (אחת) של אנשים.



רמז

צייר גרף שבו כל אדם הוא צומת. מה יקרה אם תמחק צומת כלשהו והקשתות היוצאות ממנו?

תשובה[עריכה]

נוכיח את הטענה באינדוקציה על , מספר הצמתים.

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

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



דוגמה:

בתרשים הבא, יש ל‏ 3 שכנים: 2 בעלי דרגה אי-זוגית (בלעדיו), ו1 בעל דרגה זוגית (בלעדיו).

דוגמה להוכחת משפט "לחיצת הידיים".
דוגמה להוכחת משפט "לחיצת הידיים".

לאחר הוספת , יש ל‏ 2 שכנים בעלי דרגה אי-זוגית (יחד אתו), ושכן יחיד בעל דרגה זוגית (יחד אתו). הוספת ייצרה עוד 0 צמתים בעלי דרגה אי-זוגית: עצמו בעל דרגה אי-זוגית, הפך להיות בעל דרגה זוגית, הפך להיות בעל דרגה אי-זוגית ו הפך להיות בעל דרגה זוגית.


הושבה משני צידי שולחן[עריכה]

שאלה[עריכה]

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



דוגמה:

נניח שבמסיבה יש שלשה אנשים: 1,‏ 2,‏ ו3, ורק 1 ו2 לחצו ידיים זה עם זה. אכן אפשר להושיב את 1 ו3 בצד אחד של השולחן, ואת 2 בצד השני.

תשובה[עריכה]

ניצור שתי קבוצות. הקבוצה השמאלית, תכיל בתחילה את כל הצמתים (כלומר ); הקבוצה הימנית, , תהיה ריקה בתחילה (כלומר ).

נאמר שקשת כלשהי שמחה אם ו שייכות לשתי קבוצות שונות. נגדיר כ את קבוצת הקשתות היוצאות מ, ונגדיר כ את קבוצת הקשתות השמחות היוצאות מ. לפי הגדרות אלו:

  1. בתחילה, אף קשת אינה שמחה. (.)
  2. אם לפחות חצי מהקשתות היוצאות מכל צומת שמחות, פתרנו את הבעיה. (אם , אז פתרנו את הבעיה.)

כעת, כל עוד לא פתרנו את הבעיה, נפעל כדלהלן. נבחר שרירותית צומת כלשהו מבין הצמתים שרוב קשתותיהם אינו שמח. נעביר את לקבוצה השניה.



דוגמה:

בתרשים הבא, . לכן נעביר את ל.

העברת צומת והשפעתה.
העברת צומת והשפעתה.


המשפט הבא מראה שהתהליך הוא סופי.



משפט:

בכל פעם שמעבירים צומת כלשהו כמתואר לעיל, עולה מספר הקשתות השמחות.


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

כעת נוכיח את המשפט.

הוכחה: נניח שהשכנים של בקבוצה שלו הם , ושכניו בקבוצה השניה הם . נשים לב שבהכרח .

לאחר העברת , מספר הקשתות השמחות גדל ב.