מבני נתונים ואלגוריתמים - מחברת קורס/מבחן סופי מועד א' סמסטר ב' 2007 - תשובות

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

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


שאלה 1[עריכה]

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




שאלה 2[עריכה]

נניח שזהו הגרף המקורי:

הגרף המקורי.
הגרף המקורי.


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

צמתי הגרף המשוכפל.
צמתי הגרף המשוכפל.

כעת נוסיף גם קשתות:

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

בנוסף נמתח עוד שני סוגי קשתות:

  1. לכל צומת ב, נמתח קשת במחיר בין ב לבין ‏ ב.
  2. לכל צומת ב, נמתח קשת במחיר בין ב לבין ‏ ב.(לא נצייר קשתות אלו מטעמי נוחות.)

נשים לב שאם כל הגרפים הנ"ל מיוצגים ב[[מבני נתונים ואלגוריתמים - מחברת קורס/#|]], אז סיבוכיות הבניה היא.

המשפט הבא מסביר את חשיבות הגרף החדש.



משפט:

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



הוכחה: מבניית הגרף החדש, ברור שכל מסלול מ ל ב בגרף החדש, מורכב משני חלקים:

  1. מסלול זהה לחלוטין למסלול מ ל בגרף המקורי.
  2. מסלול בעלות 1 ל ב, אם החלק הראשון זוגי, ומסלול בעלות , אם החלק הראשון אי-זוגי.


לכן, כל שנותר הוא להריץ את אלגוריתם Dijkstra.

קל לראות שהסיבוכיות הכוללת היא זו של אלגוריתם Dijkstra.

שאלה 3[עריכה]

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


הוכחה: (מעבר האינדוקציה) נניח שהטענה נכונה עד (כולל) , ונראה שהיא נכונה גם ל.





נפתור , ונקבל . עבור , נקבל שמספיק שיתקיים .

מבדיקת מספר העצים השונים, עולה שקיים מתאים גם לבסיס האינדוקציה (המקרים ).

שאלה 4[עריכה]

ראשית נניח שהמערך Mממויין, או, לחלופין, נמיין אותו בעזרת מיון מיזוג בסיבוכיות .

נגדיר כ את מירב הרווח שאפשר להרוויח מפתיחת סניפים הלקוחים מתוך הבתים הראשונים.



משפט:

לפי הגדרת :

  1. הפתרון הטוב ביותר הוא בעל רווח .
  2. הפונקציה נתונה על ידי נוסחת הנסיגה:
    • לכל ,‏
  3. מונוטונית לא-יורדת ב.



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

להלן פסוודו-קוד המממש נוסחה זו.

Max-Profit(M, P, k, i)
1	if i == 0
2		return 0
		
3	if i == 1
4		return P[1]
		
5	guess-without = Max-Profit(i - 1)
6	guess-with = P[i]
		
7	if m[i] > k
8		j = Find-Index(M, M[i] - k)
9		guess-with = guess-with + Max-Profit(M, P, k, j)
			
10	if guess-with > guess-without
11		return guess-with
12	else
13		return guess-without

חשוב רק לשים לב לקריאה לפונקציה Find-Index ב8. פונקציה זו מוצאת את האינדקס הגדול ביותר בMשקטן מM[i] - k. היות שMממויין, נוכל לעשות זאת על ידי שינוי קטן בחיפוש בינרי. נוסיף גם Memoization:

1	MP = Make-Array(n)
	
2	for i in [1, ..., n]
3		MP[i] = Nil


Max-Profit(M, P, k, i)
1	if i == 0
2		return 0
		
3	if MP[i] != Nil
4		return MP[i]
		
5	if i == 1
6		MP[1] = P[1]
7		return P[1]
		
8		guess-without = Max-Profit(i - 1)
9		guess-with = P[i]
		
10	if m[i] > k
11		j = Find-Index(M, M[i] - k)
12		guess-with = guess-with + Max-Profit(M, P, k, j)
			
13	if guess-with > guess-without
14		MP[i] = guess-with
15		return guess-with
16	else
17		MP[i] = guess-without
18		return guess-without

כעת נוסיף גם את הדפסת האיברים:

1	MP = Make-Array(n)
2	Used = Make-Array(n)
	
3	for i in [1, ..., n]
4		MP[i] = Nil


Max-Profit(M, P, k, i)
1	if i == 0
2		return 0
		
3	if MP[i] != Nil		
4		return MP[i]
		
5	if i == 1
6		MP[1] = P[1]
7		Used[1] = True
8		return P[1]
		
9		guess-without = Max-Profit(i - 1)
10		guess-with = P[i]
		
11	if m[i] > k
12		j = Find-Index(M, M[i] - k)
13		guess-with = guess-with + Max-Profit(M, P, k, j)
			
14	if guess-with > guess-without
15		MP[i] = guess-with
16		Used[i] = True
17		return guess-with
18	else
19		MP[i] = guess-without
20		Used[i] = False
21		return guess-without

המערך Used מתאר האם השתמשנו באיבר האו לא. נשתמש בו ע"י קריאה לPrint-Nums(k, n), כאשר Print-Nums מוגדרת כך:

Print-Nums(k, i)
1	if i &lt 1
2		return
		
3	if Used[i]
4		j = Find-Index(M, M[i] - k)
5		Print-Nums(k, j)
6	else
7		Print-Nums(k, i - 1)
			
8	if Used[i]
9		Print(i)

נותר רק לנתח את הסיבוכיות.

השורה j ← Find-Index(M, M[i] - k)אורכת . אם נגדיר כ את זמן הקריאה לMax-Profit(M, P, k, i)בהנחה שכל קריאה רקורסיבית היא , אז , והסיבוכיות היא . מצד שני, מיון המערך הוא , ולכן נקבל .

שאלה 5[עריכה]

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

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

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

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



דוגמה:

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

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


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



משפט:

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


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

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

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

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