דילוג לתוכן המרכזי

מתכונת 2 במדעי המחשב - יסודות מדעי המחשב 899371

1–2 יח"ל · שאלון 899371 · 6 שאלות · 2:30 שעות · פתרון מלא לכל סעיף

מבחן מתכונת במדעי המחשב, יסודות מדעי המחשב, במבנה של בחינת הבגרות. כל שאלה בו בנויה כמו שאלה מבגרות אחרת. לכל סעיף יש תשובה ופתרון מלא, וכל קוד מופיע ב-Java וב-C#. פתרו בזמן של הבחינה, ורק אחר כך פתחו את הפתרונות.

הוראות הבחינה

א. משך הבחינה: שעתיים וחצי.
ב. מבנה השאלון ומפתח ההערכה: בשאלון זה שני פרקים.
פרק ראשון – (20×2) – 40 נקודות
פרק שני – (30×2) – 60 נקודות
סך הכול – 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנוּת.
ד. הוראה מיוחדת:
את כל התוכניות שיש לכתוב בשפת מחשב כתבו בשפה אחת בלבד – Java או C#.
הערה: לא יוּרדוּ נקודות אם תכתבו בתוכניות אות גדולה במקום אות קטנה או להפך.

יש לכתוב במחברת הבחינה בלבד. יש לרשום "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.

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

בהצלחה!

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

הערה: בכל שאלה שנדרשת בה קליטה, אין צורך לבדוק את תקינות הקלט.
לפותרים בשפת Java: בכל שאלה שנדרשת בה קליטה, הניחו שבתוכנית כתובה ההוראה:
Scanner scan = new Scanner (System.in);

פרק ראשון (40 נקודות)

ענו על שתיים מן השאלות 1–3 (לכל שאלה – 20 נקודות).

שאלה 1 · מעקב אחר לולאה עם מונה זוגיים

נתון מערך arr , המכיל מספרים שלמים:

0123456
arr47310965

נתון קטע תוכנית, הכתוב בשפות Java ו־ C# :

Java

Java
int count = 0;
for (int i = 0; i < arr.length; i++)
{
   if (arr[i] % 2 == 0)
   {
      count++;
      arr[i] = arr[i] / 2;
   }
   else
      arr[i] = arr[i] * count;
}

C#

C#
int count = 0;
for (int i = 0; i < arr.Length; i++)
{
   if (arr[i] % 2 == 0)
   {
      count++;
      arr[i] = arr[i] / 2;
   }
   else
      arr[i] = arr[i] * count;
}
א.

עקבו בעזרת טבלת מעקב אחר ביצוע קטע התוכנית, ורשמו את תוכן המערך arr לאחר ביצוע קטע התוכנית.
בטבלת המעקב יש לכלול עמודה עבור כל אחד מן המשתנים האלה: i , arr[i] , count .

ב.

כתבו דוגמה למערך arr בגודל 5 , שאף אחד מן התאים שלו אינו מכיל 0 , ושלאחר ביצוע קטע התוכנית יהיו בו בדיוק שלושה תאים המכילים 0 .

◂ פתרון מלא לשאלה 1

סעיף א

תשובה

arr = {2, 7, 3, 5, 18, 3, 15}

מה נדרש: לעקוב אחרי ביצוע הלולאה על המערך הנתון (עמודות i , arr[i] , count) ולרשום את המערך בסוף.

רעיון: count סופר כמה מספרים זוגיים נמצאו עד עכשיו (כולל התא הנוכחי).

•תא זוגי: מגדילים את count באחד, והתא מתחלק ב־2.
•תא אי־זוגי: התא מוכפל ב־count – מספר הזוגיים שהופיעו לפניו.

פתרון – טבלת מעקב (לפני הלולאה: count = 0)

ii < 7 ?arr[i] זוגי?count (בסוף הסיבוב)arr[i] (בסוף הסיבוב)
0true4 – כן14 / 2 = 2
1true7 – לא17 · 1 = 7
2true3 – לא13 · 1 = 3
3true10 – כן210 / 2 = 5
4true9 – לא29 · 2 = 18
5true6 – כן36 / 2 = 3
6true5 – לא35 · 3 = 15
7false–––

המערך לאחר ביצוע קטע התוכנית:

0123456
arr273518315

בדיקה: הקטע מדפיס 2 7 3 5 18 3 15, בדיוק כמו בטבלה.

טעות נפוצה: לבדוק את הזוגיות של הערך החדש בתא, או לחשוב שהתאים 7 ו־3 "לא טופלו" – הם כן הוכפלו, אבל ב־1, ולכן ערכם לא השתנה.

סעיף ב

תשובה

למשל {7, 1, 3, 6, 5} (הופך ל־{0, 0, 0, 3, 5}). מתאים כל מערך ללא 0 שבו שלושת התאים הראשונים אי־זוגיים ו־arr[3] זוגי.

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

רעיון: מתי תא הופך ל־0?

•תא זוגי שאינו 0 מתחלק ב־2 – התוצאה אינה 0 (למשל 2 → 1).
•תא אי־זוגי מוכפל ב־count – התוצאה 0 רק אם count = 0, כלומר אם לא הופיע לפניו אף מספר זוגי.

לכן האפסים הם בדיוק התאים האי־זוגיים שמופיעים לפני הזוגי הראשון. כדי לקבל בדיוק שלושה אפסים: arr[0], arr[1], arr[2] אי־זוגיים, ו־arr[3] זוגי (אחרת יהיו ארבעה אפסים או יותר). arr[4] – כל מספר שאינו 0.

פתרון: למשל המערך:

01234
arr71365
iarr[i] זוגי?countarr[i]
07 – לא07 · 0 = 0
11 – לא01 · 0 = 0
23 – לא03 · 0 = 0
36 – כן16 / 2 = 3
45 – לא15 · 1 = 5

אחרי הביצוע: 0 , 0 , 0 , 3 , 5 – בדיוק שלושה אפסים.

בדיקה: על {7,1,3,6,5} מתקבל 0 0 0 3 5, ועל {1,3,5,2,4} מתקבל 0 0 0 1 2. בנוסף בדקנו בתוכנית את כל המערכים בגודל 5 עם ערכים מ־5− עד 5 (ללא 0): יש בדיוק שלושה אפסים אם ורק אם שלושת התאים הראשונים אי־זוגיים ו־arr[3] זוגי.

טעות נפוצה: לבחור למשל {1, 3, 5, 7, 2} – כאן ארבעה תאים אי־זוגיים מופיעים לפני הזוגי הראשון, ולכן מתקבלים ארבעה אפסים ולא שלושה.

שאלה 2 · טמפרטורות במקרר חיסונים (20 נקודות)

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

א.

כתבו פעולה חיצונית ששמה getDeviation בשפת Java או GetDeviation בשפת C# המקבלת מספר שלם – temp , המייצג טמפרטורה שנמדדה במקרר, ואת הפרמטרים low ו־ high .
הפעולה תחזיר את הסטייה של הטמפרטורה מן הטווח המותר, על פי התנאים האלה:
– אם הטמפרטורה נמוכה מ־ low , הפעולה תחזיר בכמה מעלות היא נמוכה מ־ low .
– אם הטמפרטורה גבוהה מ־ high , הפעולה תחזיר בכמה מעלות היא גבוהה מ־ high .
– אם שני התנאים שלעיל אינם מתקיימים (הטמפרטורה בטווח המותר, כולל הגבולות), הפעולה תחזיר 0 .
דוגמה: בעבור low = 2 , high = 8 : בעבור temp = 11 תחזיר 3 , בעבור temp = -1 תחזיר 3 , בעבור temp = 8 תחזיר 0 .

ב.

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

כתבו פעולה חיצונית ששמה getAllDeviations בשפת Java או GetAllDeviations בשפת C# המקבלת את המערך temps ואת הפרמטרים low ו־ high .
הפעולה תחזיר מערך חדש מטיפוס שלם בגודל זהה למערך temps , המציג בכל תא את הסטייה של המדידה שנמצאת באותו האינדקס במערך temps (על פי סעיף א).
דוגמה: בעבור low = 2 , high = 8 , והמערך temps :

אינדקס0123456
temps591171-18

יוחזר המערך שלהלן:

אינדקס0123456
0130130

הערות: – יש להשתמש בפעולה שכתבתם בסעיף א.
– אין לשנות את המערך temps .

ג.

משלוח חיסונים נפסל אם מתקיים בו לפחות אחד מן התנאים האלה:
– יש מדידה שבה הסטייה גדולה מ־ 3 מעלות.
– יש שתי מדידות רצופות (בשני תאים סמוכים במערך) שבשתיהן הטמפרטורה מחוץ לטווח המותר.

כתבו פעולה חיצונית ששמה isSafe בשפת Java או IsSafe בשפת C# , המקבלת את המערך temps ואת הפרמטרים low ו־ high .
הפעולה תחזיר true אם המשלוח לא נפסל, אחרת הפעולה תחזיר false .
דוגמה: בעבור המערך הנתון בסעיף ב הפעולה תחזיר false , כי במדידות באינדקסים 1 ו־ 2 , שהן רצופות, הטמפרטורה מחוץ לטווח המותר (אף שאין במערך מדידה שבה הסטייה גדולה מ־ 3).
הערה: יש להשתמש בפעולה שכתבתם בסעיף ב.

◂ פתרון מלא לשאלה 2

סעיף א

תשובה

temp < low → low − temp ; temp > high → temp − high ; אחרת 0

מה נדרש: פעולה המחזירה בכמה מעלות הטמפרטורה חורגת מן הטווח [low, high], או 0 אם היא בתוכו.

רעיון: אם temp < low – החריגה היא המרחק עד low, כלומר low − temp (מספר חיובי). אם temp > high – החריגה היא temp − high. אחרת הטמפרטורה בטווח (כולל הגבולות) ומחזירים 0.

פתרון: הקוד המלא – בלשונית Java / C#.

Java
if (temp < low) return low - temp;
if (temp > high) return temp - high;
return 0;

בדיקה: low = 2, high = 8: עבור 11 → 3, עבור -1 → 2 − (−1) = 3, עבור 2 → 0, עבור 8 → 0, עבור 5 → 0.

טעות נפוצה: להחזיר temp − low כאשר הטמפרטורה נמוכה מדי – מתקבל מספר שלילי (עבור -1: −3) במקום הסטייה החיובית 3.

הקוד המלא
public static int getDeviation(int temp, int low, int high)
{
    if (temp < low)
        return low - temp;
    if (temp > high)
        return temp - high;
    return 0;
}

סעיף ב

תשובה

result[i] = getDeviation(temps[i], low, high) לכל i, במערך חדש

מה נדרש: מערך חדש באותו גודל, שבו כל תא הוא הסטייה של המדידה המתאימה.

רעיון: יוצרים מערך result בגודל temps.length ועוברים על כל האינדקסים: result[i] = getDeviation(temps[i], low, high). המערך temps רק נקרא.

פתרון: הקוד המלא – בלשונית Java / C#.

בדיקה: על המערך מהדוגמה (low = 2, high = 8) התקבל [0, 1, 3, 0, 1, 3, 0], כמו בשאלה, והמערך temps נשאר ללא שינוי.

הקוד המלא
public static int[] getAllDeviations(int[] temps, int low, int high)
{
    int[] result = new int[temps.length];
    for (int i = 0; i < temps.length; i++)
    {
        result[i] = getDeviation(temps[i], low, high);
    }
    return result;
}

סעיף ג

תשובה

על מערך הסטיות: אם dev[i] > 3, או dev[i] > 0 וגם dev[i − 1] > 0 (i > 0) – מחזירים false; אחרי הלולאה true

מה נדרש: להחזיר true אם אין מדידה עם סטייה גדולה מ־ 3 ואין שתי מדידות רצופות מחוץ לטווח.

רעיון: מקבלים את מערך הסטיות dev מ־ getAllDeviations. מדידה מחוץ לטווח היא מדידה שהסטייה שלה גדולה מ־ 0. עוברים על המערך: אם dev[i] > 3 – המשלוח נפסל. אם i > 0 ושני התאים dev[i] ו־ dev[i − 1] גדולים מ־ 0 – שתי מדידות רצופות מחוץ לטווח, והמשלוח נפסל. אם הלולאה הסתיימה בלי לפסול – מחזירים true.

פתרון: הקוד המלא – בלשונית Java / C#.

בדיקה (low = 2, high = 8):

tempsסטיותתוצאה
5, 9, 11, 7, 1, -1, 80, 1, 3, 0, 1, 3, 0false (אינדקסים 1, 2)
5, 11, 4, -1, 80, 3, 0, 3, 0true
5, 12, 50, 4, 0false (סטייה 4)
5, 6, 9, 10, 0, 1, 1false (אינדקסים 2, 3)
-2, 54, 0false (סטייה 4 באינדקס 0)

טעות נפוצה: לבדוק dev[i + 1] בלולאה עד i < dev.length – חריגה מגבולות המערך בתא האחרון. לכן משווים כל תא לתא שלפניו ומתחילים את בדיקת הזוג מ־ i = 1 (התנאי i > 0).

הקוד המלא
public static boolean isSafe(int[] temps, int low, int high)
{
    int[] dev = getAllDeviations(temps, low, high);
    for (int i = 0; i < dev.length; i++)
    {
        if (dev[i] > 3)
            return false;
        if (i > 0 && dev[i] > 0 && dev[i - 1] > 0)
            return false;
    }
    return true;
}

שאלה 3 · כרטיס הגרלה (20 נקודות)

"כרטיס הגרלה" הוא מערך מטיפוס שלם שבו כל תא מכיל מספר שלם בין 1 ל־ 37 (כולל), וכל המספרים בכרטיס שונים זה מזה.
ממלאים כרטיס הגרלה תא אחר תא, החל מתא 0 , עד שכל התאים מלאים. בכל שלב:
i. מוגרל מספר שלם בין 1 ל־ 37 .
ii. המספר שהוגרל מוצב בתא הבא שיש למלא.

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

כתבו פעולה חיצונית ששמה fillTicket בשפת Java או FillTicket בשפת C# המקבלת מערך מטיפוס שלם – arr (שגודלו בין 1 ל־ 37) וממלאת אותו כ"כרטיס הגרלה".
הפעולה תדפיס את ערכי התאים לפי הסדר לאחר המילוי (כל ערך בשורה חדשה).

כתבו פעולה חיצונית ששמה fillTicket בשפת Java או FillTicket בשפת C# המקבלת מערך מטיפוס שלם – arr (שגודלו בין 1 ל־ 37) וממלאת אותו כ"כרטיס הגרלה".
הפעולה תדפיס את ערכי התאים לפי הסדר לאחר המילוי (כל ערך בשורה חדשה).

◂ פתרון מלא לשאלה 3

פתרון

תשובה

לולאת while עם מונה count של התאים שמולאו; בכל סיבוב מגרילים num בין 1 ל־ 37 , מחפשים אותו בתאים 0..count-1 , ורק אם לא נמצא – arr[count] = num ו־ count++; בסוף מדפיסים את המערך, ערך בכל שורה.

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

רעיון:

•מגרילים מספר בין 1 ל־ 37 בעזרת rnd.nextInt(37) + 1 ב־ Java או rnd.Next(37) + 1 ב־ C# (‏nextInt(37) נותן 0 עד 36).
•המונה count שומר כמה תאים כבר מולאו – וזה גם האינדקס של התא הבא שיש למלא.
•כיוון שהגרלה של מספר שכבר קיים אינה נספרת, אי אפשר להשתמש בלולאת for שעוברת פעם אחת על כל תא. משתמשים בלולאת while שרצה כל עוד count < arr.length , ו־ count גדל רק כאשר המספר הוצב.
•כדי לדעת אם המספר כבר קיים – חיפוש סדרתי בתאים שכבר מולאו בלבד (0 עד count-1).

פתרון:

public static void fillTicket(int[] arr)
{
    Random rnd = new Random();
    int count = 0;
    while (count < arr.length)
    {
        int num = rnd.nextInt(37) + 1;
        boolean found = false;
        for (int i = 0; i < count; i++)
        {
            if (arr[i] == num)
                found = true;
        }
        if (!found)
        {
            arr[count] = num;
            count++;
        }
    }
    for (int i = 0; i < arr.length; i++)
    {
        System.out.println(arr[i]);
    }
}

(ב־ Java צריך import java.util.Random; בראש הקובץ. אפשר גם להגריל בעזרת (int)(Math.random() * 37) + 1 .)

בדיקה: על מערך בגודל 6 מתקבל למשל 37 30 28 8 34 23 – כל הערכים בין 1 ל־ 37 , שונים זה מזה, והשורות שמודפסות זהות לתאי המערך. בדיקה קשה יותר: מערך בגודל 37 – הכרטיס חייב להכיל בדיוק את כל המספרים 1 עד 37 . ובמערך בגודל 37 מתקבל תמיד סידור של כל 37 המספרים.

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

הקוד המלא
public static void fillTicket(int[] arr)
{
    Random rnd = new Random();
    int count = 0;
    while (count < arr.length)
    {
        int num = rnd.nextInt(37) + 1;
        boolean found = false;
        for (int i = 0; i < count; i++)
        {
            if (arr[i] == num)
                found = true;
        }
        if (!found)
        {
            arr[count] = num;
            count++;
        }
    }
    for (int i = 0; i < arr.length; i++)
    {
        System.out.println(arr[i]);
    }
}

פרק שני (60 נקודות)

ענו על שתיים מן השאלות 4–6 (לכל שאלה – 30 נקודות).

שאלה 4 · מכולות של פולי קפה – מערך עצמים (30 נקודות)

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

נתונה המחלקה Sack המייצגת שק של פולי קפה ולה שתי תכונות: ארץ המקור של הפולים – origin, ומשקל השק בקילוגרמים – weight (מספר ממשי חיובי).

Java
public class Sack{
      private String origin;
      private double weight;
}

בנוסף, נתונה המחלקה Container המייצגת מכולה ולה שתי תכונות: קוד המכולה – code, ומערך של עצמים sacks מטיפוס Sack בגודל מספר השקים במכולה.

Java
public class Container{
      private String code;
      private Sack[] sacks;
}

הניחו שקיימות פעולות get ו־set בשפת Java ופעולות Get ו־Set בשפת C# בעבור כל התכונות בשתי המחלקות.

לפניכם ממשק חלקי של המחלקה Container:

תיאור הפעולהכותרת הפעולה
פעולה בונה המקבלת את קוד המכולה ואת מספר השקים שבה, ומאתחלת את התכונות. המערך sacks מאותחל למערך ריק בגודל numpublic Container(String code, int num)
פעולה המחזירה את המשקל הכולל (בקילוגרמים) של כל השקים במכולה.Java – public double totalWeight()<br>C# – public double TotalWeight()
פעולה המקבלת משקל מרבי limit (בקילוגרמים). הפעולה מחזירה true אם המשקל הכולל של השקים במכולה גדול מ־limit, אחרת מחזירה false.Java – public boolean isOverweight(double limit)<br>C# – public bool IsOverweight(double limit)
א.

ממשו את הפעולה הבונה של המחלקה Container.

ב.

ממשו את הפעולה isOverweight (בשפת C#: IsOverweight) במחלקה Container.
ניתן להשתמש בפעולה totalWeight של המחלקה Container מבלי לממש אותה.
הניחו כי איברי המערך sacks שונים מ־null.

ג.

מכולה יכולה לצאת למשלוח אם המשקל הכולל של השקים בה אינו גדול מהמשקל המרבי המותר.
כתבו פעולה חיצונית ששמה printReady (בשפת C#: PrintReady) המקבלת מערך של עצמים – port מטיפוס Container, המייצג את המכולות שבנמל, ומשקל מרבי מותר limit. הפעולה תדפיס את הקודים של כל המכולות שיכולות לצאת למשלוח.
חובה להשתמש בפעולה isOverweight של המחלקה Container.
הניחו כי איברי המערכים port ו־sacks שונים מ־null.

◂ פתרון מלא לשאלה 4

סעיף א

תשובה

this.code = code; sacks = new Sack[num];

מה נדרש: לממש את הפעולה הבונה Container(code, num).

רעיון: הפעולה מציבה את הקוד בתכונה code ויוצרת מערך חדש של num הפניות לעצמים מטיפוס Sack (תאיו null – השקים עוד לא הוכנסו). כיוון ששם הפרמטר code זהה לשם התכונה, חובה לכתוב this.code = code;.

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה: אחרי new Container("TST-1", 4) התקבל (בשתי השפות): code = "TST-1", אורך sacks הוא 4, ו־sacks[3] הוא null.

טעות נפוצה: לכתוב code = code; – ההשמה היא של הפרמטר לעצמו, והתכונה code נשארת null.

הקוד המלא
public Container(String code, int num)
{
    this.code = code;
    this.sacks = new Sack[num];
}

סעיף ב

תשובה

return this.totalWeight() > limit;

מה נדרש: להחזיר true אם המשקל הכולל של המכולה גדול מ־limit.

רעיון: את המשקל הכולל מחשבת הפעולה totalWeight, שמותר להשתמש בה בלי לממש אותה. מזמנים אותה על העצם הנוכחי ומחזירים ישירות את תוצאת ההשוואה totalWeight() > limit (אין צורך ב־if).

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה (limit = 180):

מכולהמשקלי השקיםמשקל כוללisOverweight(180)
BR-10160, 60, 60.5180.5true
ET-20269, 69, 69, 69276true
CO-30370, 70, 35175false
KE-40459.9, 60, 60179.9false
VN-505100, 100, 100300true

טעות נפוצה: לכתוב >= – מכולה שמשקלה שווה בדיוק ל־limit אינה חורגת (ראו VN-505 עם limit = 300 בסעיף ג).

הקוד המלא
public boolean isOverweight(double limit)
{
    return this.totalWeight() > limit;
}

סעיף ג

תשובה

לכל i: אם !port[i].isOverweight(limit) – מדפיסים port[i].getCode().

מה נדרש: פעולה חיצונית שמדפיסה את הקודים של המכולות שמשקלן אינו גדול מ־limit.

רעיון: עוברים על כל המכולות. מכולה יכולה לצאת למשלוח בדיוק כאשר isOverweight(limit) מחזירה false, ולכן התנאי הוא השלילה !port[i].isOverweight(limit). את limit מעבירים הלאה לפעולה של המכולה. הקוד מודפס בעזרת getCode(), כי התכונה code פרטית.

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה: על חמש המכולות מהטבלה בסעיף ב מודפסים:

•עם limit = 180: CO-303, KE-404.
•עם limit = 300: כל חמש המכולות, כולל VN-505 שמשקלה 300 בדיוק.

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

הקוד המלא
public static void printReady(Container[] port, double limit)
{
    for (int i = 0; i < port.length; i++)
    {
        if (!port[i].isOverweight(limit))
            System.out.println(port[i].getCode());
    }
}

שאלה 5 · קרונות רכבת – מערך של עצמים (30 נקודות)

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

נתונה המחלקה Wagon – קרון, ולה שלוש תכונות:

•number – המספר הסידורי של הקרון, מספר שלם
•seats – מספר המושבים בקרון, מספר שלם (0 בקרון שאין בו מושבים)
•cargo – סוג המטען, מחרוזת (מחרוזת ריקה בקרון שאין בו מטען)

הניחו שיש פעולות get/Get ו־set/Set בעבור תכונות המחלקה. ניתן להשתמש בפעולות המחלקה מבלי לממש אותן.

נתון ממשק חלקי של המחלקה Wagon:

תיאור הפעולהכותרת הפעולה
פעולה בונה המקבלת ערכים בעבור תכונות המחלקהpublic Wagon(int number, int seats, String cargo)
פעולה המחזירה true אם הקרון הוא קרון נוסעים, אחרת היא מחזירה falseJava – public boolean isPassenger()<br>C# – public bool IsPassenger()
פעולה המחזירה true אם הקרון הוא קרון משא, אחרת היא מחזירה falseJava – public boolean isFreight()<br>C# – public bool IsFreight()
פעולה המחזירה true אם הקרון הוא קרון מכל, אחרת היא מחזירה falseJava – public boolean isTanker()<br>C# – public bool IsTanker()
פעולה המחזירה true אם הקרון אינו קרון נוסעים, אינו קרון משא ואינו קרון מכל, אחרת היא מחזירה falseJava – public boolean isOther()<br>C# – public bool IsOther()

נתונה המחלקה Train – רכבת, ולה תכונה אחת בלבד:

•wagons – מערך מטיפוס Wagon בגודל N, ובו קרונות הרכבת לפי סדרם.
1.

רכבת נקראת מאוזנת אם ההפרש בין כל שניים מבין שלושת המספרים – מספר קרונות הנוסעים, מספר קרונות המשא ומספר קרונות המכל – הוא לכל היותר 1.
לדוגמה, רכבת שיש בה 3 קרונות נוסעים, 2 קרונות משא ו־3 קרונות מכל היא מאוזנת. רכבת שיש בה 3 קרונות נוסעים, קרון משא אחד ו־2 קרונות מכל אינה מאוזנת.
כתבו פעולה פנימית במחלקה Train ששמה isBalanced בשפת Java או IsBalanced בשפת C#.
הפעולה תחזיר true אם הרכבת מאוזנת, אחרת הפעולה תחזיר false.
שימו לב: הקרונות האחרים אינם משפיעים על התשובה.

2.

לצורך ניקיון מחלקים את הרכבת למקטעים של m קרונות רצופים: הקרונות בתאים 0 עד m−1 הם המקטע הראשון, הקרונות בתאים m עד 2m−1 הם המקטע השני, וכן הלאה.
כתבו פעולה פנימית במחלקה Train ששמה hasFullSection בשפת Java או HasFullSection בשפת C#, המקבלת מספר שלם m.
הפעולה תחזיר true אם קיים מקטע כך שכל הקרונות בו הם קרונות נוסעים. אחרת, הפעולה תחזיר false.
הניחו כי m חיובי ו־N מתחלק ב־m ללא שארית.

לדוגמה, בעבור הרכבת:

01234567
משאנוסעיםנוסעיםנוסעיםנוסעיםמכלמכלקטר

hasFullSection(4) תחזיר false, ו־hasFullSection(2) תחזיר true (התאים 2–3).

◂ פתרון מלא לשאלה 5

סעיף 1

תשובה

סופרים passenger/freight/tanker; max = המקסימום של השלושה, min = המינימום; מחזירים max - min <= 1.

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

רעיון:

1.שלושה מונים; לולאה על כל הקרונות, ולכל קרון שואלים isPassenger / isFreight / isTanker ומגדילים את המונה המתאים. קרונות "אחרים" לא נספרים.
2.ההפרש בין כל שניים מהמונים הוא לכל היותר 1 בדיוק כאשר ההפרש בין הגדול ביותר לקטן ביותר הוא לכל היותר 1. לכן מחשבים max ו־min של שלושת המונים (בעזרת Math.max / Math.Max פעמיים) ומחזירים max - min <= 1.

(אפשר גם לבדוק ישירות שלוש השוואות בערך מוחלט: |p−f| ≤ 1 && |p−t| ≤ 1 && |f−t| ≤ 1.)

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה (נ – נוסעים, מ – משא, כ – מכל, א – אחר):

•נ, נ, מ, כ – 2, 1, 1 ⇒ true.
•נ, מ, כ, נ, מ, כ, א, א – 2, 2, 2 ⇒ true.
•נ, נ, מ, מ, כ, א – 2, 2, 1 ⇒ true.
•נ, נ, נ, מ, מ, כ, א, א – 3, 2, 1: ההפרש בין 3 ל־1 הוא 2 ⇒ false.
•א, א, א, א – 0, 0, 0 ⇒ true.

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

הקוד המלא
public boolean isBalanced()
{
    int passenger = 0, freight = 0, tanker = 0;
    for (int i = 0; i < wagons.length; i++)
    {
        if (wagons[i].isPassenger())
            passenger++;
        if (wagons[i].isFreight())
            freight++;
        if (wagons[i].isTanker())
            tanker++;
    }
    int max = Math.max(passenger, Math.max(freight, tanker));
    int min = Math.min(passenger, Math.min(freight, tanker));
    return max - min <= 1;
}

סעיף 2

תשובה

לכל start = 0, m, 2m, ...: all = true; כל קרון בתאים start..start+m−1 שאינו isPassenger מאפס את all; אם all נשאר true – return true. בסוף return false.

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

רעיון: "קיים מקטע כך שלכל קרון בו ...":

•לולאה חיצונית על תחילת המקטע: start = 0, m, 2m, ... (קפיצות של m, כי המקטעים אינם חופפים). כיוון ש־N מתחלק ב־m, המקטע האחרון מסתיים בדיוק בסוף המערך.
•לכל מקטע: all = true, ולולאה פנימית על התאים start עד start+m−1. קרון שאינו קרון נוסעים הופך את all ל־false.
•מקטע שבו all נשאר true ⇒ מחזירים true. אם אין כזה ⇒ false.

פתרון: הקוד המלא – בלשונית Java/C#.

בדיקה:

•הרכבת מהדוגמה: m = 4 ⇒ false (המקטעים הם משא–נוסעים–נוסעים–נוסעים ו־נוסעים–מכל–מכל–קטר), m = 2 ⇒ true (המקטע 2–3), m = 1 ⇒ true.
•8 קרונות נוסעים: m = 4 ⇒ true.
•קטר, מזנון, קטר, מזנון: m = 1 ⇒ false.

טעות נפוצה: לחפש 4 קרונות נוסעים רצופים בכל מקום ברכבת (start++ במקום start += m). בדוגמה יש 4 קרונות נוסעים רצופים בתאים 1–4, אבל הם אינם מקטע אחד, ולכן התשובה בעבור m = 4 היא false.

הקוד המלא
public boolean hasFullSection(int m)
{
    for (int start = 0; start < wagons.length; start += m)
    {
        boolean all = true;   // נניח שכל קרונות המקטע הם קרונות נוסעים
        for (int j = start; j < start + m; j++)
        {
            if (!wagons[j].isPassenger())
                all = false;
        }
        if (all)
            return true;
    }
    return false;
}

שאלה 6 · מספרי הרשד (30 נקודות)

מספר שלם חיובי – num ייקרא "מספר הרשד" אם num מתחלק ללא שארית בסכום הספרות שלו.

דוגמה למספר הרשד: המספר 18 , כי סכום הספרות שלו הוא 1 + 8 = 9 , ו־ 18 מתחלק ב־ 9 ללא שארית.
דוגמה נוספת למספר הרשד: המספר 201 , כי סכום הספרות שלו הוא 3 , ו־ 201 מתחלק ב־ 3 ללא שארית (201 = 3 · 67).
דוגמה למספר שאינו מספר הרשד: המספר 19 , כי סכום הספרות שלו הוא 10 , ו־ 19 אינו מתחלק ב־ 10 ללא שארית.

א.(1)

כתבו פעולה חיצונית ששמה isHarshad בשפת Java או IsHarshad בשפת C#, המקבלת מספר שלם חיובי – num . הפעולה מחזירה true אם הוא מספר הרשד, אחרת היא מחזירה false .

(2)

כתבו פעולה חיצונית ששמה printHarshad בשפת Java או PrintHarshad בשפת C#, המקבלת שני מספרים שלמים חיוביים: low , high . הפעולה תדפיס את כל מספרי הרשד שבין שני מספרים אלה (כולל).
הניחו ש־ low קטן מ־ high או שווה לו.
הערה: אפשר להיעזר בפעולה שכתבתם בתת־סעיף (1).
דוגמה: בעבור low=10 ו־ high=21 הפעולה תדפיס 10 , 12 , 18 , 20 , 21 .
הסבר: המספר 10 הוא מספר הרשד (סכום הספרות 1), המספר 11 אינו מספר הרשד (סכום הספרות 2 ו־ 11 אי־זוגי), המספר 12 הוא מספר הרשד (סכום הספרות 3), וכן הלאה.

ב.

רצף של מספרי הרשד הוא כמה מספרים עוקבים שכולם מספרי הרשד. למשל, 20 , 21 הם רצף של שני מספרי הרשד.
יש השערה שלא קיים רצף של שישה מספרי הרשד עוקבים בין המספרים 10 עד 999,999 (כולל).
כתבו פעולה חיצונית ששמה noSixInRow בשפת Java או NoSixInRow בשפת C#, המחזירה true אם אכן מבין כל המספרים 10 עד 999,999 (כולל) אין שישה מספרי הרשד עוקבים. אחרת היא מחזירה false .
הערה: אפשר להיעזר בפעולה שכתבתם בתת־סעיף א(1).

◂ פתרון מלא לשאלה 6

סעיף א(1)

תשובה

מחשבים את סכום הספרות sum (לולאת % 10 ו-/ 10 על עותק של num) ומחזירים num % sum == 0.

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

רעיון
מפרקים את המספר לספרות בלולאה: הספרה הימנית היא temp % 10, ואחר כך מקצצים אותה בעזרת temp / 10, עד ש-temp מגיע ל-0. עובדים על עותק (temp) כי את num עצמו צריך בסוף לבדיקת החלוקה. num חיובי, ולכן sum ≥ 1 ואין חלוקה באפס.

פתרון
Java

Java
// סעיף א(1)
public static boolean isHarshad(int num)
{
    int sum = 0;
    int temp = num;
    while (temp > 0)
    {
        sum = sum + temp % 10;
        temp = temp / 10;
    }
    return num % sum == 0;
}

C#

C#
// סעיף א(1)
public static bool IsHarshad(int num)
{
    int sum = 0;
    int temp = num;
    while (temp > 0)
    {
        sum = sum + temp % 10;
        temp = temp / 10;
    }
    return num % sum == 0;
}

בדיקה

•isHarshad(18) ← sum = 9, 18 % 9 = 0 ← true
•isHarshad(19) ← sum = 10, 19 % 10 = 9 ← false
•isHarshad(201) ← true ; isHarshad(1729) ← sum = 19, 1729 = 19 · 91 ← true ; isHarshad(101) ← false
•כל מספר חד-ספרתי הוא מספר הרשד (7 % 7 = 0).

בין 1 ל-999 יש 212 מספרי הרשד.

טעות נפוצה: לפרק את num עצמו (num = num / 10) ואז לבדוק num % sum – בסוף הלולאה num כבר 0, והתשובה תמיד true.

הקוד המלא
// סעיף א(1)
public static boolean isHarshad(int num)
{
    int sum = 0;
    int temp = num;
    while (temp > 0)
    {
        sum = sum + temp % 10;
        temp = temp / 10;
    }
    return num % sum == 0;
}

סעיף א(2)

תשובה

for (i = low; i <= high; i++) if (isHarshad(i)) מדפיסים את i.

מה נדרש
להדפיס את כל מספרי הרשד בתחום [low, high], כולל הקצוות.

רעיון
לולאה על כל המספרים מ-low עד high (כולל), ולכל מספר קריאה לפעולה מסעיף א(1).

פתרון
Java

Java
// סעיף א(2)
public static void printHarshad(int low, int high)
{
    for (int i = low; i <= high; i++)
    {
        if (isHarshad(i))
        {
            System.out.println(i);
        }
    }
}

C#

C#
// סעיף א(2)
public static void PrintHarshad(int low, int high)
{
    for (int i = low; i <= high; i++)
    {
        if (IsHarshad(i))
        {
            Console.WriteLine(i);
        }
    }
}

בדיקה

•printHarshad(10, 21) ← 10, 12, 18, 20, 21 (בדיוק כמו בדוגמה)
•printHarshad(131050, 131058) ← 131050, 131052, 131053, 131054, 131055, 131056, 131058

טעות נפוצה: לכתוב i < high – אז high עצמו (למשל 21 בדוגמה) לא נבדק.

הקוד המלא
// סעיף א(2)
public static void printHarshad(int low, int high)
{
    for (int i = low; i <= high; i++)
    {
        if (isHarshad(i))
        {
            System.out.println(i);
        }
    }
}

סעיף ב

תשובה

מונה run: גדל ב-1 בכל מספר הרשד ומתאפס במספר שאינו מספר הרשד; אם run מגיע ל-6 מחזירים false; בסוף מחזירים true. (התוצאה: true – הרצף הארוך ביותר בתחום הוא באורך 5, 131052–131056.)

מה נדרש
לבדוק אם בתחום 10–999,999 יש שישה מספרים עוקבים שכולם מספרי הרשד; להחזיר true אם אין רצף כזה.

רעיון
עוברים על המספרים לפי הסדר ומחזיקים מונה run – אורך הרצף הנוכחי של מספרי הרשד שמסתיים במספר הנוכחי. אם i הוא מספר הרשד – run גדל ב-1; אחרת – run מתאפס. ברגע ש-run מגיע ל-6 נמצא רצף כזה, ומחזירים false מיד. אם הלולאה הסתיימה – מחזירים true.

פתרון
Java

Java
// סעיף ב
public static boolean noSixInRow()
{
    int run = 0;   // אורך הרצף הנוכחי של מספרי הרשד עוקבים
    for (int i = 10; i <= 999999; i++)
    {
        if (isHarshad(i))
        {
            run++;
            if (run == 6)
            {
                return false;
            }
        }
        else
        {
            run = 0;
        }
    }
    return true;
}

C#

C#
// סעיף ב
public static bool NoSixInRow()
{
    int run = 0;   // אורך הרצף הנוכחי של מספרי הרשד עוקבים
    for (int i = 10; i <= 999999; i++)
    {
        if (IsHarshad(i))
        {
            run++;
            if (run == 6)
            {
                return false;
            }
        }
        else
        {
            run = 0;
        }
    }
    return true;
}

בדיקה
הפעולה מחזירה true. הרצף הארוך ביותר בתחום 10–999,999 הוא באורך 5, והוא מופיע פעמיים – 131052 עד 131056 ו-491424 עד 491428. (שימו לב: מחוץ לתחום יש רצפים ארוכים יותר – למשל 1 עד 10 הם עשרה מספרי הרשד עוקבים – ולכן ההשערה מנוסחת מ-10.)

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

הקוד המלא
// סעיף ב
public static boolean noSixInRow()
{
    int run = 0;   // אורך הרצף הנוכחי של מספרי הרשד עוקבים
    for (int i = 10; i <= 999999; i++)
    {
        if (isHarshad(i))
        {
            run++;
            if (run == 6)
            {
                return false;
            }
        }
        else
        {
            run = 0;
        }
    }
    return true;
}
טבלת התשובות
שאלהסעיףתשובה
1א

arr = {2, 7, 3, 5, 18, 3, 15}

ב

למשל {7, 1, 3, 6, 5} (הופך ל־{0, 0, 0, 3, 5}). מתאים כל מערך ללא 0 שבו שלושת התאים הראשונים אי־זוגיים ו־arr[3] זוגי.

2א

temp < low → low − temp ; temp > high → temp − high ; אחרת 0

ב

result[i] = getDeviation(temps[i], low, high) לכל i, במערך חדש

ג

על מערך הסטיות: אם dev[i] > 3, או dev[i] > 0 וגם dev[i − 1] > 0 (i > 0) – מחזירים false; אחרי הלולאה true

3-

לולאת while עם מונה count של התאים שמולאו; בכל סיבוב מגרילים num בין 1 ל־ 37 , מחפשים אותו בתאים 0..count-1 , ורק אם לא נמצא – arr[count] = num ו־ count++; בסוף מדפיסים את המערך, ערך בכל שורה.

4א

this.code = code; sacks = new Sack[num];

ב

return this.totalWeight() > limit;

ג

לכל i: אם !port[i].isOverweight(limit) – מדפיסים port[i].getCode().

51

סופרים passenger/freight/tanker; max = המקסימום של השלושה, min = המינימום; מחזירים max - min <= 1.

2

לכל start = 0, m, 2m, ...: all = true; כל קרון בתאים start..start+m−1 שאינו isPassenger מאפס את all; אם all נשאר true – return true. בסוף return false.

6א(1)

מחשבים את סכום הספרות sum (לולאת % 10 ו-/ 10 על עותק של num) ומחזירים num % sum == 0.

א(2)

for (i = low; i <= high; i++) if (isHarshad(i)) מדפיסים את i.

ב

מונה run: גדל ב-1 בכל מספר הרשד ומתאפס במספר שאינו מספר הרשד; אם run מגיע ל-6 מחזירים false; בסוף מחזירים true. (התוצאה: true – הרצף הארוך ביותר בתחום הוא באורך 5, 131052–131056.)

כל האתר במבט אחד

קיצורי דרך לכל הכלים, הבגרויות והקורסים

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