04. Branching — Homework Solutions

The answer .cpp files are in exercises/04/homework/solutions/.

Open this page after trying on your own. Compare your line of reasoning with the How to think about it section, not the code line by line: two pieces of code that look different can both be correct, and what you should imitate is the way of getting there. The Tests section of each problem contains inputs and outputs that have been checked — run your own answer with those inputs before considering yourself done.

Running one of the answers:

g++ -std=c++17 -O2 -o jawab exercises/04/homework/solutions/01-ganjil-genap.cpp
./jawab

Problem 1 — Odd or even

Problem. Read one integer, print genap ("even") or ganjil ("odd"), including for negative numbers.

How to think about it. n % 2 is 0 for even numbers. For negative numbers, C++ gives -1 (not 1) for odd numbers. That is why checking n % 2 == 0 is safe, while checking n % 2 == 1 is wrong for -3.

Walkthrough.

int n;
cin >> n;

if (n % 2 == 0) cout << "genap\n";
else cout << "ganjil\n";

Tests.

Input Output
4 genap
7 ganjil
0 genap
-4 genap

The -4 case is the core of the problem. Checking n % 2 == 0 is safe for negative numbers, but checking n % 2 == 1 for "odd" is not: -7 % 2 is -1 in C++, not 1, so -7 would be wrongly classified as even. Always safe: check == 0 and put the odd case in the else.

Common mistakes.

  • Writing if (n % 2 == 1) and then failing on negative input.
  • Writing if (n = 2). A single = assigns a value, and the condition becomes always true.

Problem 2 — Largest of three

Problem. Print the largest of three numbers, without max.

How to think about it. Do not try to write out every possible ordering — there are six, and ties make it even messier. Use the reigning champion pattern: assume the first number is the largest, then challenge it one by one. This pattern will be used again later to find the largest value in an array.

Ties resolve themselves because the comparison is > (not >=): when two numbers are equal, the first one stays and the printed result is still correct.

Walkthrough.

int besar = a;
if (b > besar) besar = b;
if (c > besar) besar = c;

cout << besar << "\n";

Tests.

Input Output
3 9 5 9
7 7 7 7
-5 -2 -9 -2

The last two rows are the edge cases the problem asks for: equal values must not make the program fail to choose, and data that is entirely negative must not be answered with 0.

Common mistakes.

  • Writing if (a > b && a > c) ... else if (b > a && b > c) ... and then forgetting one branch, so that nothing is printed for the input 5 5 3.

Problem 3 — Leap year

Problem. Print KABISAT ("leap year") or BUKAN ("not").

How to think about it. The "except, except again" rule is easier to write as a single logical expression:

  • divisible by 400 → definitely a leap year, or
  • divisible by 4 and not divisible by 100.

Walkthrough.

bool kabisat = (tahun % 400 == 0) || (tahun % 4 == 0 && tahun % 100 != 0);

if (kabisat) cout << "KABISAT\n";
else cout << "BUKAN\n";

The nested form below is also correct, and sometimes easier to read:

if (tahun % 4 != 0) cout << "BUKAN\n";
else if (tahun % 100 != 0) cout << "KABISAT\n";
else if (tahun % 400 != 0) cout << "BUKAN\n";
else cout << "KABISAT\n";

Tests.

Input Output Reason
2024 KABISAT divisible by 4, not a multiple of 100
2023 BUKAN not divisible by 4
1900 BUKAN multiple of 100, not a multiple of 400
2000 KABISAT multiple of 400

Those four rows represent the four branches of the rule. If even one of them is not tested, a mistake in the order of the checks can slip through unnoticed.

Common mistakes.

  • Checking only tahun % 4 == 0, so 1900 is answered as a leap year.
  • Putting the % 100 check before the % 400 check in the || form, so the year 2000 is answered as not a leap year.

Problem 4 — Triangle type

Problem. Determine whether three sides form a triangle, and then its type.

How to think about it. The triangle condition: the sum of the two shortest sides must be greater than the longest side. To avoid checking three pairs, first sort the three values so that a <= b <= c; after that a single check a + b <= c is enough.

Sorting three values by hand takes three swaps: a–b, b–c, then a–b once more.

The order of the type checks also matters: check equilateral first, then isosceles. If reversed, an equilateral triangle also gets caught as isosceles.

Walkthrough.

if (a > b) { int t = a; a = b; b = t; }
if (b > c) { int t = b; b = c; c = t; }
if (a > b) { int t = a; a = b; b = t; }

if (a + b <= c) {
    cout << "BUKAN SEGITIGA\n";
} else if (a == b && b == c) {
    cout << "SAMA SISI\n";
} else if (a == b || b == c) {
    cout << "SAMA KAKI\n";
} else {
    cout << "SEMBARANG\n";
}

Tests.

Input Output
3 3 3 SAMA SISI
5 5 8 SAMA KAKI
3 4 5 SEMBARANG
1 2 10 BUKAN SEGITIGA

The order of the checks matters: the "not a triangle" condition must be checked first. Otherwise, 1 2 10 would be answered SEMBARANG even though those three sides cannot form a triangle at all.

Common mistakes.

  • Using a + b < c as the failure condition. A triangle with sides 1 2 3 does not exist (its three points are collinear), so the sign must be <=.
  • Forgetting to sort, then checking only one pair of sides.
  • Checking isosceles before equilateral.

Challenge — Ticket price

Problem. Several discount rules can apply at the same time; take the cheapest.

How to think about it. Building an if / else if chain here makes things hard, because else if stops at the first rule that matches — while the problem asks for the cheapest among all the rules that match. The right pattern: keep the best price so far, then check each rule separately and update it if it is cheaper. This is the reigning champion pattern again, this time looking for the smallest.

The umur < 5 rule is separated at the end because its value is always zero and beats everything.

Walkthrough.

const int DASAR = 50000;
int harga = DASAR;

int setengah = DASAR / 2;          // 25000
int diskon20 = DASAR * 80 / 100;   // 40000

if (umur >= 5 && umur <= 17 && setengah < harga) harga = setengah;
if (pelajar == 1 && umur >= 18 && diskon20 < harga) harga = diskon20;
if (umur >= 60 && setengah < harga) harga = setengah;
if (umur < 5) harga = 0;

cout << harga << "\n";

Check with the input 65 1: a student aged 65. The student rule gives 40000, the senior rule gives 25000; the answer is 25000.

Tests.

Input Output Winning rule
4 0 0 under 5: free
12 1 25000 age 5–17: half
20 1 40000 adult student: 20% discount
65 0 25000 60 and above: half
30 0 50000 no discount

Look at the 12 1 row: age 12 with student status hits two rules at once. The one used is the cheapest, which is half price, not the 20 percent discount.

Common mistakes.

  • Using else if so that a senior student still pays 40000.
  • Computing the discount with DASAR * 0.8 and then printing it as a double, so the output is 40000.0 and the judge rejects it. Multiply first, then divide (DASAR * 80 / 100) so it stays an integer.

OSN-style exercises — walkthrough

The answer files are in exercises/04/osn/solutions/.

Problem 1 — Parking Fee

How to think about it. There are four rules, and three of them are mutually exclusive, so the shape is an if / else if / else chain. The order follows the rules from the most specific: zero duration first, then the first two hours, then the rest.

The part that needs thought is "or part of an hour". That phrase means rounding up, and rounding up for integers is written (sisa + 59) / 60: adding 59 pushes any remainder, however small, past the next multiple of 60.

The upper limit of 50000 is not a separate branch but a cap applied at the end, because it applies to any result.

Walkthrough.

int durasi = keluar - masuk;
int tarif;

if (durasi == 0) {
    tarif = 0;
} else if (durasi <= 120) {
    tarif = 5000;
} else {
    int sisa = durasi - 120;
    int jam = (sisa + 59) / 60;       // round up
    tarif = 5000 + 3000 * jam;
    if (tarif > 50000) tarif = 50000;
}

cout << tarif << "\n";

Tests.

Input Output What is checked
480 480 0 zero duration
480 600 5000 exactly 120 minutes, no extra yet
480 601 8000 one minute over already counts as an hour
600 780 8000 exactly three hours
0 1440 50000 maximum fee

The second and third rows are a pair that must be tested together: they differ by only one minute, and that is where the most common mistake lies.

Common mistakes.

  • Using sisa / 60, which rounds down, so 121 minutes is charged 5000.
  • Writing the 50000 limit as an else if branch, so it does not apply to the computation in other branches.
  • Forgetting to separate the zero duration, so parking for zero minutes is charged 5000.

Problem 2 — Digital Clock

How to think about it. One day has 86400 seconds. Since a digital clock does not show the date, the extra days are discarded with % 86400. After that, the breakdown uses the same / and % pair as splitting digits in Chapter 03:

  • hours: hari / 3600
  • minutes: (hari % 3600) / 60
  • seconds: hari % 60

The HH:MM:SS part requires two digits, so numbers below 10 need a leading 0. Since setw and setfill have not been covered yet, that zero is printed separately with an if.

Walkthrough.

long long hari = t % 86400;
long long jam = hari / 3600;
long long menit = (hari % 3600) / 60;
long long detik = hari % 60;

if (jam < 10) cout << "0";
cout << jam << ":";
if (menit < 10) cout << "0";
cout << menit << ":";
if (detik < 10) cout << "0";
cout << detik << "\n";

With <iomanip>, those three pairs of lines can be shortened to cout << setw(2) << setfill('0') << jam and so on. Both are correct.

Tests.

Input Output What is checked
0 00:00:00 all parts zero
3661 01:01:01 sample from the problem
86399 23:59:59 last second of the day
86400 00:00:00 exactly one full day
1000000000 01:46:40 T far above one day

Common mistakes.

  • Forgetting % 86400, so a large T prints an hour greater than 23.
  • Computing minutes as hari / 60 instead of (hari % 3600) / 60.
  • Printing 1:1:1. The HH:MM:SS format requires two digits in every part.

Problem 3 — Contest Judges

How to think about it. Each judge is checked with the same pattern, so the check is written three times in identical form. Note that there are three possibilities per judge, not two: A wins, B wins, or no one is chosen. That is why the shape is if / else if without an else — the third case really does nothing.

After the votes are counted, the final comparison also has three possibilities.

Walkthrough.

int suaraA = 0, suaraB = 0;

if (a1 > b1) suaraA++;
else if (b1 > a1) suaraB++;

if (a2 > b2) suaraA++;
else if (b2 > a2) suaraB++;

if (a3 > b3) suaraA++;
else if (b3 > a3) suaraB++;

if (suaraA > suaraB) cout << "A\n";
else if (suaraB > suaraA) cout << "B\n";
else cout << "SERI\n";

Tests.

Input Output What is checked
9 8 7 9 10 6 A sample from the problem
1 2 3 3 4 5 B a judge who chooses no one
5 5 5 5 5 5 SERI no judge chooses anyone

The third case matters: the result is a tie not because the votes are equal in number, but because there are no votes at all. An answer that only compares "who has more" without a final else branch will print an empty line in this case.

Common mistakes.

  • Using else in the per-judge check, so equal scores count as a win for B.
  • Adding up the three judges' scores and comparing the totals. That is a different problem: a contestant can win on total score but lose on judge votes, as in 1 10 5 4 5 4.
  • Printing Seri or seri. The problem asks for SERI.

If you are still stuck

  • The if chain picks the wrong branch → Chapter 04, the tracing table in the section if, else if, else.
  • Translating problem sentences into conditions → Chapter 04, section Translating problem sentences into conditions.
  • Combining several conditions → Chapter 04, section Combining conditions and its truth table.

Before moving on to Chapter 05, make sure you can write the condition for "age is between 5 and 17" and its negation, without hesitating over the < and <= signs.