04. Branching

Up to this point a program runs exactly the same way every time it is run. This chapter adds conditions: questions answered with true or false, where the answer determines which part of the code is executed.

Comparison operators

Operator Meaning
== equal to
!= not equal to
< less than
> greater than
<= less than or equal to
>= greater than or equal to

The result has type bool: true (printed as 1) or false (printed as 0).

cout << (7 == 7) << "\n";    // 1
cout << (7 != 8) << "\n";    // 1
cout << (3 >= 5) << "\n";    // 0

In C++, false is 0 and true is 1. Conversely, every nonzero value is considered true. That is why if (x) is valid and means "if x is not zero", and if (n % 2) means "if n is odd".

== compares, = assigns a value. if (x = 7) is not a syntax error in C++ — it sets x to 7 and then treats the condition as true. The program becomes wrong without a single compiler message. Double-check every = inside an if.

if, else if, else

int nilai = 73;

if (nilai >= 90) {
    cout << "A\n";
} else if (nilai >= 80) {
    cout << "B\n";
} else if (nilai >= 70) {
    cout << "C\n";
} else if (nilai >= 60) {
    cout << "D\n";
} else {
    cout << "E\n";
}

How to read it: imagine the value 73 walking down a staircase and stopping at the first step it can pass.

nilai >= 90 >= 80 >= 70 >= 60 printed
95 yes — — — A
90 yes — — — A
89 no yes — — B
73 no no yes — C
59 no no no no E

The — mark means that condition is never checked: once one branch is chosen, the rest are skipped entirely.

Note also that the branch else if (nilai >= 80) does not need to be written as nilai >= 80 && nilai < 90. If that line is reached at all, nilai >= 90 has already been shown to be false. Adding the second condition is not wrong, it only makes the code longer and easier to mistype.

C++ checks the conditions from top to bottom and stops at the first one that is true. The order therefore determines the result: if nilai >= 60 is placed at the top, every passing score will get D.

Curly braces may be omitted if the body is a single statement:

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

In contests, that one-line form is often used because it is faster to write. But as soon as the body grows to two statements, curly braces must be added. Forgetting to add them produces a bug that is hard to spot:

if (a > b)
    cout << a << "\n";
    cout << "terbesar\n";   // always printed, regardless of the condition

Open exercises/04/01-nilai-huruf.cpp. Change nilai to exactly 90, 89, 70, and 59, recompiling each time, and make sure the >= boundaries behave as you expect.

Combining conditions

Operator Meaning
&& and — true if both sides are true
|| or — true if either side is true
! not — flips true and false

The truth table:

a b a && b a || b !a
false false false false true
false true false true true
true false false true false
true true true true false

In short: && requires both, || needs only one of them.

int umur = 14;
bool punya_izin = true;

if (umur >= 12 && punya_izin) cout << "boleh ikut\n";
if (umur < 12 || !punya_izin) cout << "belum boleh ikut\n";

In mathematics we write 1 <= x <= 10. In C++ that form does not mean the same thing: 1 <= x is computed first into 0 or 1, then compared with 10 — the result is always true. Write x >= 1 && x <= 10.

Short-circuit evaluation

&& stops evaluating as soon as its left side is false, and || stops as soon as its left side is true. This property is used to guard checks:

if (i < n && a[i] == target) ...

If i < n is false, a[i] is never touched — this is what prevents the program from reading outside the array. Swapping the order can make the program crash.

Negating a condition

Sometimes it is easier to write the opposite of a condition. The negation rules (De Morgan's laws) are only two lines, and worth memorizing:

Condition Its negation
a && b !a || !b
a || b !a && !b
x >= 1 && x <= 10 x < 1 || x > 10

Note that && turns into || when negated. A common mistake: the opposite of "age is between 5 and 17" is written umur < 5 && umur > 17 — a condition that can never be true, so its branch is never executed.

Translating problem sentences into conditions

Most branching mistakes in contests happen while translating the problem's Indonesian sentences into comparison signs, not while writing the code:

Sentence in the problem Indonesian wording Its condition
"more than k" "lebih dari k" x > k
"at most k", "no more than k" "paling banyak k", "tidak lebih dari k" x <= k
"at least k", "minimum k" "paling sedikit k", "minimal k" x >= k
"between a and b" (inclusive) "antara a dan b" (termasuk ujungnya) x >= a && x <= b
"outside the range a–b" "di luar rentang a–b" x < a || x > b
"a multiple of k", "divisible by k" "kelipatan k", "habis dibagi k" x % k == 0
"a and b are different" "a dan b berbeda" a != b
"either a or b is even" "salah satu dari a atau b genap" a % 2 == 0 || b % 2 == 0
"both are even" "keduanya genap" a % 2 == 0 && b % 2 == 0

The phrases "at most" ("paling banyak") and "at least" ("paling sedikit") are the most costly source of off-by-one mistakes, because the program still runs and is only wrong on data at the boundary. When in doubt, test with the value exactly at the boundary — for "at most 10", check x = 10 and x = 11.

Open exercises/04/04-pola-soal.cpp. It contains several conditions that often appear in problems. Add one new condition: print BISA if a number is divisible by 3 and not divisible by 9.

switch

When one integer variable is compared against many fixed values, switch is tidier:

int hari;
cin >> hari;

switch (hari) {
    case 1: cout << "Senin\n"; break;
    case 2: cout << "Selasa\n"; break;
    case 3: cout << "Rabu\n"; break;
    default: cout << "hari lain\n";
}

break is required in every case; without it, the program continues executing the next case (called fall-through). switch only works for integer types and char, not for string or ranges such as nilai >= 90.

In contests, switch is rarely used because if can do everything. It still needs to be recognized, because regency-level OSN problems often show a switch fragment and ask what its output is — and the answer depends on whether break is present or not.

Open exercises/04/03-switch.cpp. Remove one break, recompile, then run it with input that hits that case. Notice that two lines are printed at once.

The ternary operator

The form kondisi ? nilai_jika_benar : nilai_jika_salah (condition ? value_if_true : value_if_false) picks one of two values in a single statement:

int a = 7, b = 12;
int besar = (a > b) ? a : b;
cout << (besar % 2 == 0 ? "genap" : "ganjil") << "\n";

Useful for short cases. For logic with many branches, if is still easier to read.

Open exercises/04/02-logika.cpp, then change umur and punya_izin until every output line has appeared at least once.

Patterns that often appear in problems

// even or odd
if (n % 2 == 0) ...

// multiple
if (n % 5 == 0) ...

// within a range
if (x >= 1 && x <= 100) ...

// larger of two
int besar = (a > b) ? a : b;

// sign of a number
if (n > 0) cout << "positif\n";
else if (n < 0) cout << "negatif\n";
else cout << "nol\n";

Homework

Problem 1 — Odd or even

Open exercises/04/homework/01-ganjil-genap.cpp. Read one integer and print genap ("even") or ganjil ("odd"). Also test with negative numbers — make sure your answer is still correct for -4.

Problem 2 — Largest of three

Open exercises/04/homework/02-terbesar.cpp. Read three integers and print the largest. Use only if and comparison operators, no max, no arrays. Make sure your answer is still correct if two of the numbers are equal.

Problem 3 — Leap year

Open exercises/04/homework/03-kabisat.cpp. Read a year and print KABISAT ("leap year") or BUKAN ("not"). The rule: divisible by 4, except when divisible by 100, except again when divisible by 400. So 2000 is a leap year, 1900 is not.

Problem 4 — Triangle type

Open exercises/04/homework/04-segitiga.cpp. Read three positive integers as side lengths. Print BUKAN SEGITIGA ("not a triangle") if the sum of the two shortest sides does not exceed the longest side. If it is a triangle, print one of SAMA SISI (equilateral), SAMA KAKI (isosceles), or SEMBARANG (scalene).

Challenge — Ticket price

Open exercises/04/homework/05-tiket.cpp. Read an age and a student status (1 for a student, 0 otherwise). The base price is 50000. The discount rules:

  • age under 5: free,
  • age 5 to 17: pay half,
  • students aged 18 and above: 20 percent discount,
  • age 60 and above: pay half,
  • otherwise: full price.

If more than one rule applies, use the cheapest. Print the price as an integer.

Most common mistakes

What was written Consequence
if (x = 7) assigns instead of comparing; the condition is always true
if (1 <= x <= 10) always true; write x >= 1 && x <= 10
if (a > b); the semicolon closes the if; its body always runs
two statements without { } only the first statement is subject to the condition
else if order reversed the looser branch catches everything first
case without break the next branch runs as well
> when the problem says "at most" off by one at the boundary

A semicolon after if is the mistake that is hardest to see with the eye, because the code still compiles without any warning:

if (n % 2 == 0);              // this semicolon closes the if
    cout << "genap\n";        // always printed

OSN tips

Branching problems are reading problems. At early OSN levels, most if problems are not technically difficult; what trips people up is a single rule sentence that was missed. A helpful habit: copy the list of rules into comments above the code, one rule per line, then cross them off one by one after turning each into an if.

Test exactly at the boundary, not in the middle. If a rule says "age 17 and below", test with 16, 17, and 18 — not with 10 and 40. Almost all branching mistakes hide in a single number at the boundary, and OSN test files almost always include that number.

The order of branches is part of the answer. An if / else if chain stops at the first branch that is true. More specific rules must be checked before general rules:

if (n % 100 == 0) ...        // specific: multiple of 100
else if (n % 4 == 0) ...     // general: multiple of 4

If the order is swapped, the second branch is never reached for 100, 200, 300, and so on.

If the problem says "choose the most favorable", do not use an else if chain. Overlapping rules do not produce one branch, but several candidate answers. Compute all the candidates, then take the smallest or largest as the problem requires.

Text output must match exactly. If the problem asks for YA and TIDAK, then Ya, ya, or YES are all judged wrong. Copy the words from the problem text; do not retype them from memory.

The edge cases most often forgotten:

Problem shape Edge cases that must be tested
numbers can be negative -1, 0, and an even -n such as -4
there is a division a denominator of 0
there is a range a to b a, b, a-1, b+1
comparing three values all three equal, two equal and one different
there is a time or distance difference a difference of zero

if (x = 5) is not a comparison but an assignment that is always true. The compiler often gives only a warning, not an error, so the program still builds and is still wrong. If a branch is always entered when it should not be, check the number of = signs first.

Summary

  • A comparison result has type bool; false is 0, and every nonzero value is considered true.
  • An if / else if / else chain is checked from the top and stops at the first branch that is true, so the order determines the result.
  • && requires both sides to be true, || needs only one, ! negates. When negated, && becomes || and vice versa.
  • && and || stop evaluating as soon as the result is certain; this property is used to guard checks such as i < n && a[i] == x.
  • Write ranges as x >= 1 && x <= 10, not 1 <= x <= 10.
  • Branching mistakes come more often from mistranslating the problem's sentences than from writing the code wrong. Always test with values exactly at the boundary.

OSN-style exercises

The following three problems are pure branching problems: no loops, no arrays, but the rules are layered as in real problems. Work through the list of rules one by one, and test exactly at the boundaries.

The starter files for all three are in exercises/04/osn/.

Problem 1 — Parking Fee

A building computes its parking fee with the following rules:

  • the first two hours are charged a flat fee of 5000 rupiah;
  • each subsequent hour, or part of an hour, adds 3000 rupiah;
  • the fee for one day never exceeds 50000 rupiah;
  • a vehicle that enters and exits in the same minute is not charged.

Input format. One line containing two integers M and K: the minute the vehicle enters and the minute the vehicle exits, counted from 00:00.

Output format. One line containing the parking fee in rupiah.

Constraints. 0 ≤ M ≤ K ≤ 1440.

Sample input

480 601

Sample output

8000

Explanation. The vehicle is parked for 601 − 480 = 121 minutes. The first two hours (120 minutes) are charged 5000. The remainder is 1 minute, and even one minute counts as a full hour, so 3000 is added. The total is 8000.

Starter file: exercises/04/osn/01-tarif-parkir.cpp

Problem 2 — Digital Clock

A digital clock shows the time in the format HH:MM:SS, each part exactly two digits. The clock is switched on at 00:00:00 and left running for T seconds. Determine the digits shown on its display at the end of the experiment.

Input format. One line containing one integer T.

Output format. One line containing the time in the format HH:MM:SS.

Constraints. 0 ≤ T ≤ 10⁹.

Sample input

3661

Sample output

01:01:01

Explanation. 3661 seconds is 1 hour, 1 minute, and 1 second. Note that T may be more than one day: a digital clock does not show the date, so the extra days are ignored. For T = 86400, the display goes back to 00:00:00.

Starter file: exercises/04/osn/02-jam-digital.cpp

Problem 3 — Contest Judges

Two contestants, A and B, are scored by three judges. Each judge gives one score to A and one score to B. A judge is considered to choose the contestant to whom they gave the higher score; if they give the same score to both, that judge chooses no one.

The winner is the contestant chosen by more judges. If both are chosen by the same number of judges, the result is a tie.

Input format. One line containing six integers a1 b1 a2 b2 a3 b3: A's score and B's score from the first judge, then from the second judge, then from the third judge.

Output format. One line containing A, B, or SERI ("tie").

Constraints. Every score is between 0 and 100.

Sample input

9 8 7 9 10 6

Sample output

A

Explanation. The first judge chooses A (9 > 8), the second judge chooses B (9 > 7), the third judge chooses A (10 > 6). A gets two votes, B one vote.

Starter file: exercises/04/osn/03-juri-lomba.cpp

Confused, or already done? Open the homework solutions page.