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"; // 0In 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 conditionOpen
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 printedOSN 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 4If 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;falseis0, and every nonzero value is considered true. - An
if / else if / elsechain 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 asi < n && a[i] == x.- Write ranges as
x >= 1 && x <= 10, not1 <= 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.