04. Percabangan
Sampai sini program berjalan sama persis setiap kali dijalankan. Bab ini menambahkan kondisi: pertanyaan yang dijawab benar atau salah, dan jawabannya menentukan bagian kode mana yang dijalankan.
Operator perbandingan
| Operator | Arti |
|---|---|
== |
sama dengan |
!= |
tidak sama dengan |
< |
kurang dari |
> |
lebih dari |
<= |
kurang dari atau sama dengan |
>= |
lebih dari atau sama dengan |
Hasilnya bertipe bool: true (dicetak
1) atau false (dicetak 0).
cout << (7 == 7) << "\n"; // 1
cout << (7 != 8) << "\n"; // 1
cout << (3 >= 5) << "\n"; // 0Di C++, false adalah 0 dan
true adalah 1. Sebaliknya, setiap
nilai yang bukan nol dianggap benar. Itulah sebabnya
if (x) sah ditulis dan berarti "kalau x tidak
nol", dan if (n % 2) berarti "kalau n
ganjil".
== membandingkan, = memberi nilai.
if (x = 7) bukan error sintaks di C++ — ia mengisi
x dengan 7 lalu menganggap kondisinya benar. Program jadi
salah tanpa satu pun pesan compiler. Periksa ulang setiap =
di dalam 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";
}Cara membacanya: bayangkan nilai 73 menuruni tangga dan
berhenti di anak tangga pertama yang bisa dilewati.
nilai |
>= 90 |
>= 80 |
>= 70 |
>= 60 |
tercetak |
|---|---|---|---|---|---|
| 95 | ya | — | — | — | A |
| 90 | ya | — | — | — | A |
| 89 | tidak | ya | — | — | B |
| 73 | tidak | tidak | ya | — | C |
| 59 | tidak | tidak | tidak | tidak | E |
Tanda — berarti kondisi itu tidak pernah
diperiksa: begitu satu cabang terpilih, sisanya dilewati
seluruhnya.
Perhatikan juga bahwa cabang else if (nilai >= 80)
tidak perlu ditulis
nilai >= 80 && nilai < 90. Kalau baris itu
sampai diperiksa, berarti nilai >= 90 sudah terbukti
salah. Menambahkan syarat kedua tidak salah, hanya membuat kode lebih
panjang dan lebih mudah salah ketik.
C++ memeriksa kondisi dari atas ke bawah dan
berhenti di yang pertama benar. Urutan karena itu menentukan hasil:
kalau nilai >= 60 diletakkan paling atas, semua nilai
lulus akan mendapat D.
Kurung kurawal boleh dihilangkan kalau isinya satu pernyataan:
if (n % 2 == 0) cout << "genap\n";
else cout << "ganjil\n";Di lomba, bentuk satu baris itu sering dipakai karena lebih cepat ditulis. Tetapi begitu isinya bertambah jadi dua pernyataan, kurung kurawal wajib ditambahkan. Lupa menambahkannya menghasilkan bug yang sulit terlihat:
if (a > b)
cout << a << "\n";
cout << "terbesar\n"; // selalu dicetak, tidak peduli kondisinyaBuka
exercises/04/01-nilai-huruf.cpp.
Ubah nilai menjadi tepat 90, 89, 70, dan 59, compile ulang
tiap kali, dan pastikan batas >= berperilaku seperti
dugaanmu.
Menggabungkan kondisi
| Operator | Arti |
|---|---|
&& |
dan — benar jika kedua sisi benar |
|| |
atau — benar jika salah satu sisi benar |
! |
bukan — membalik benar dan salah |
Tabel kebenarannya:
a |
b |
a && b |
a || b |
!a |
|---|---|---|---|---|
| salah | salah | salah | salah | benar |
| salah | benar | salah | benar | benar |
| benar | salah | salah | benar | salah |
| benar | benar | benar | benar | salah |
Ringkasnya: && menuntut
keduanya, || cukup salah
satu.
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";Dalam matematika kita menulis 1 <= x <= 10. Di C++
bentuk itu tidak berarti demikian:
1 <= x dihitung dulu menjadi 0 atau
1, lalu dibandingkan dengan 10 — hasilnya
selalu benar. Tulis x >= 1 && x <= 10.
Hubung singkat
&& berhenti menghitung begitu sisi kirinya
salah, dan || berhenti begitu sisi kirinya benar. Sifat ini
dipakai untuk mengamankan pemeriksaan:
if (i < n && a[i] == target) ...Kalau i < n salah, a[i] tidak pernah
disentuh — ini yang mencegah program membaca di luar array. Menukar
urutannya membuat program bisa berhenti mendadak.
Membalik kondisi
Kadang lebih mudah menuliskan kebalikan sebuah syarat. Aturan pembaliknya (hukum De Morgan) hanya dua baris, dan layak dihafal:
| Kondisi | Kebalikannya |
|---|---|
a && b |
!a || !b |
a || b |
!a && !b |
x >= 1 && x <= 10 |
x < 1 || x > 10 |
Perhatikan bahwa && berubah menjadi
|| saat dibalik. Kesalahan yang sering terjadi: kebalikan
dari "umurnya antara 5 dan 17" ditulis
umur < 5 && umur > 17 — syarat yang mustahil
benar, sehingga cabangnya tidak pernah dijalankan.
Menerjemahkan kalimat soal menjadi kondisi
Sebagian besar kesalahan percabangan di lomba terjadi saat menerjemahkan kalimat Indonesia menjadi tanda pembanding, bukan saat menulis kodenya:
| Kalimat di soal | Kondisinya |
|---|---|
"lebih dari k" |
x > k |
"paling banyak k", "tidak lebih dari
k" |
x <= k |
"paling sedikit k", "minimal k" |
x >= k |
"antara a dan b" (termasuk ujungnya) |
x >= a && x <= b |
"di luar rentang a–b" |
x < a || x > b |
"kelipatan k", "habis dibagi k" |
x % k == 0 |
"a dan b berbeda" |
a != b |
"salah satu dari a atau b genap" |
a % 2 == 0 || b % 2 == 0 |
| "keduanya genap" | a % 2 == 0 && b % 2 == 0 |
Kata "paling banyak" dan "paling sedikit" adalah sumber kesalahan
satu langkah yang paling mahal, karena programnya tetap jalan dan hanya
salah pada data di tepi batas. Kalau ragu, uji dengan nilai tepat di
batasnya — untuk "paling banyak 10", periksa x = 10 dan
x = 11.
Buka
exercises/04/04-pola-soal.cpp.
Di dalamnya ada beberapa kondisi yang sering muncul di soal. Tambahkan
satu kondisi baru: mencetak BISA kalau sebuah bilangan
habis dibagi 3 dan tidak habis dibagi 9.
switch
Kalau satu variabel bulat dibandingkan dengan banyak nilai tetap,
switch lebih rapi:
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 wajib ada di setiap case; tanpanya,
program lanjut mengerjakan case berikutnya (disebut
fall-through). switch hanya bekerja untuk tipe
bulat dan char, tidak untuk string atau
rentang seperti nilai >= 90.
Di lomba, switch jarang dipakai karena if
bisa mengerjakan semuanya. Ia tetap perlu dikenali, karena soal OSN
tingkat kabupaten sering menampilkan potongan
switch lalu bertanya apa keluarannya — dan jawabannya
bergantung pada ada atau tidaknya break.
Buka
exercises/04/03-switch.cpp.
Hapus satu break, compile ulang, lalu jalankan dengan
masukan yang mengenai case itu. Perhatikan dua baris ikut
tercetak sekaligus.
Operator tiga bagian
Bentuk kondisi ? nilai_jika_benar : nilai_jika_salah
memilih satu dari dua nilai dalam satu pernyataan:
int a = 7, b = 12;
int besar = (a > b) ? a : b;
cout << (besar % 2 == 0 ? "genap" : "ganjil") << "\n";Berguna untuk kasus pendek. Untuk logika bercabang banyak,
if tetap lebih mudah dibaca.
Buka
exercises/04/02-logika.cpp,
lalu ubah umur dan punya_izin sampai setiap
baris keluaran pernah muncul.
Pola yang sering muncul di soal
// genap atau ganjil
if (n % 2 == 0) ...
// kelipatan
if (n % 5 == 0) ...
// di dalam rentang
if (x >= 1 && x <= 100) ...
// terbesar dari dua
int besar = (a > b) ? a : b;
// tanda bilangan
if (n > 0) cout << "positif\n";
else if (n < 0) cout << "negatif\n";
else cout << "nol\n";Pekerjaan rumah
Soal 1 — Ganjil atau genap
Buka
exercises/04/homework/01-ganjil-genap.cpp.
Baca satu bilangan bulat, cetak genap atau
ganjil. Uji juga dengan bilangan negatif — pastikan
jawabanmu tetap benar untuk -4.
Soal 2 — Terbesar dari tiga
Buka
exercises/04/homework/02-terbesar.cpp.
Baca tiga bilangan bulat, cetak yang terbesar. Pakai if dan
operator perbandingan saja, tanpa max, tanpa array.
Pastikan jawabanmu tetap benar jika ada dua angka yang sama besar.
Soal 3 — Tahun kabisat
Buka
exercises/04/homework/03-kabisat.cpp.
Baca satu tahun, cetak KABISAT atau BUKAN.
Aturannya: habis dibagi 4, kecuali habis dibagi 100,
kecuali lagi habis dibagi 400. Jadi 2000 kabisat, 1900
bukan.
Soal 4 — Jenis segitiga
Buka
exercises/04/homework/04-segitiga.cpp.
Baca tiga bilangan bulat positif sebagai panjang sisi. Cetak
BUKAN SEGITIGA bila jumlah dua sisi terpendek tidak
melebihi sisi terpanjang. Kalau segitiga, cetak salah satu dari
SAMA SISI, SAMA KAKI, atau
SEMBARANG.
Tantangan — Harga tiket
Buka
exercises/04/homework/05-tiket.cpp.
Baca umur dan status pelajar (1 untuk pelajar,
0 bukan). Harga dasar 50000. Aturan diskonnya:
- umur di bawah 5 tahun: gratis,
- umur 5 sampai 17 tahun: bayar setengah,
- pelajar berumur 18 tahun ke atas: diskon 20 persen,
- umur 60 tahun ke atas: bayar setengah,
- selain itu: harga penuh.
Kalau lebih dari satu aturan cocok, pakai yang paling murah. Cetak harganya sebagai bilangan bulat.
Kesalahan yang paling sering
| Yang ditulis | Akibatnya |
|---|---|
if (x = 7) |
mengisi, bukan membandingkan; kondisinya selalu benar |
if (1 <= x <= 10) |
selalu benar; tulis
x >= 1 && x <= 10 |
if (a > b); |
titik koma menutup if; isinya selalu dijalankan |
dua pernyataan tanpa { } |
hanya pernyataan pertama yang ikut kondisi |
urutan else if terbalik |
cabang yang longgar menangkap semuanya lebih dulu |
case tanpa break |
cabang berikutnya ikut dijalankan |
> padahal soal berkata "paling banyak" |
salah satu langkah di tepi batas |
Titik koma setelah if adalah kesalahan yang paling sulit
dilihat mata, karena kodenya tetap di-compile tanpa peringatan apa
pun:
if (n % 2 == 0); // titik koma ini menutup if
cout << "genap\n"; // selalu dicetakTips OSN
Soal percabangan adalah soal membaca. Di OSN tingkat
awal, sebagian besar soal if tidak sulit secara teknik;
yang menjatuhkan adalah satu kalimat aturan yang terlewat. Kebiasaan
yang menolong: salin daftar aturannya ke dalam komentar di atas kode,
satu baris satu aturan, lalu coret satu per satu setelah ditulis menjadi
if.
Uji tepat di batas, bukan di tengah. Kalau aturan berbunyi "umur 17 tahun ke bawah", uji dengan 16, 17, dan 18 — bukan dengan 10 dan 40. Hampir semua kesalahan percabangan bersembunyi di satu angka di perbatasan, dan berkas uji OSN hampir selalu memuat angka itu.
Urutan cabang adalah bagian dari jawaban. Rantai
if / else if berhenti di cabang pertama yang benar. Aturan
yang lebih khusus harus diperiksa lebih dulu daripada aturan umum:
if (n % 100 == 0) ... // khusus: kelipatan 100
else if (n % 4 == 0) ... // umum: kelipatan 4Kalau urutannya ditukar, cabang kedua tidak pernah tercapai untuk 100, 200, 300, dan seterusnya.
Kalau soal menyebut "pilih yang paling menguntungkan", jangan
memakai rantai else if. Aturan yang saling tumpang
tindih tidak menghasilkan satu cabang, melainkan beberapa calon jawaban.
Hitung semua calonnya, lalu ambil yang terkecil atau terbesar sesuai
permintaan soal.
Keluaran teks harus sama persis. Kalau soal meminta
YA dan TIDAK, maka Ya,
ya, atau YES semuanya dinilai salah. Salin
kata-katanya dari teks soal, jangan diketik ulang dari ingatan.
Kasus tepi yang paling sering dilupakan:
| Bentuk soal | Kasus tepi yang wajib diuji |
|---|---|
| bilangan bisa negatif | -1, 0, dan -n genap seperti
-4 |
| ada pembagian | penyebut bernilai 0 |
ada rentang a sampai b |
a, b, a-1,
b+1 |
| membandingkan tiga nilai | ketiganya sama, dua sama satu berbeda |
| ada selisih waktu atau jarak | selisih nol |
if (x = 5) bukan perbandingan, melainkan penugasan yang
selalu bernilai benar. Compiler sering hanya memberi peringatan, bukan
error, sehingga programnya tetap jadi dan tetap salah. Kalau sebuah
cabang selalu dimasuki padahal seharusnya tidak, periksa jumlah tanda
= lebih dulu.
Ringkasan
- Hasil perbandingan bertipe
bool;falseadalah0, dan setiap nilai bukan nol dianggap benar. - Rantai
if / else if / elsediperiksa dari atas dan berhenti di cabang pertama yang benar, jadi urutannya menentukan hasil. &&menuntut kedua sisi benar,||cukup salah satu,!membalik. Saat dibalik,&&menjadi||dan sebaliknya.&&dan||berhenti menghitung begitu hasilnya sudah pasti; sifat ini dipakai untuk mengamankan pemeriksaan sepertii < n && a[i] == x.- Tulis rentang sebagai
x >= 1 && x <= 10, bukan1 <= x <= 10. - Kesalahan percabangan lebih sering lahir dari salah menerjemahkan kalimat soal daripada dari salah menulis kode. Uji selalu dengan nilai tepat di batasnya.
Latihan bergaya OSN
Ketiga soal berikut adalah soal percabangan murni: tidak ada perulangan, tidak ada array, tetapi aturannya bertumpuk seperti pada soal sungguhan. Kerjakan daftar aturannya satu per satu, dan uji tepat di batasnya.
Kerangka ketiganya ada di
exercises/04/osn/.
Soal 1 — Tarif Parkir
Sebuah gedung menghitung tarif parkir dengan aturan berikut:
- dua jam pertama dikenakan tarif tetap 5000 rupiah;
- setiap jam berikutnya, atau bagian dari jam, ditambah 3000 rupiah;
- tarif satu hari tidak pernah melebihi 50000 rupiah;
- kendaraan yang masuk dan keluar pada menit yang sama tidak dikenakan biaya.
Format masukan. Satu baris berisi dua bilangan bulat
M dan K: menit kendaraan masuk dan menit
kendaraan keluar, dihitung sejak pukul 00:00.
Format keluaran. Satu baris berisi tarif parkir dalam rupiah.
Batasan. 0 ≤ M ≤ K ≤
1440.
Contoh masukan
480 601
Contoh keluaran
8000
Penjelasan. Kendaraan parkir selama 601 − 480 = 121 menit. Dua jam pertama (120 menit) dikenakan 5000. Sisanya 1 menit, dan satu menit pun dihitung sebagai satu jam penuh, sehingga ditambah 3000. Totalnya 8000.
Kerangkanya:
exercises/04/osn/01-tarif-parkir.cpp
Soal 2 — Jam Digital
Sebuah jam digital menampilkan waktu dalam format
HH:MM:SS, masing-masing tepat dua digit. Jam itu dinyalakan
pada pukul 00:00:00 dan dibiarkan berjalan selama T detik.
Tentukan angka yang tertera di layarnya pada akhir percobaan.
Format masukan. Satu baris berisi satu bilangan
bulat T.
Format keluaran. Satu baris berisi waktu dalam
format HH:MM:SS.
Batasan. 0 ≤ T ≤ 10⁹.
Contoh masukan
3661
Contoh keluaran
01:01:01
Penjelasan. 3661 detik adalah 1 jam, 1 menit, dan 1
detik. Perhatikan bahwa T boleh lebih dari satu hari: jam
digital tidak menunjukkan tanggal, jadi kelebihan harinya diabaikan.
Untuk T = 86400, layarnya kembali ke
00:00:00.
Kerangkanya:
exercises/04/osn/02-jam-digital.cpp
Soal 3 — Juri Lomba
Dua peserta, A dan B, dinilai oleh tiga juri. Setiap juri memberi satu nilai untuk A dan satu nilai untuk B. Juri dianggap memilih peserta yang ia beri nilai lebih tinggi; kalau ia memberi nilai yang sama untuk keduanya, juri itu tidak memilih siapa pun.
Pemenangnya adalah peserta yang dipilih oleh lebih banyak juri. Kalau keduanya dipilih oleh jumlah juri yang sama, hasilnya seri.
Format masukan. Satu baris berisi enam bilangan
bulat a1 b1 a2 b2 a3 b3: nilai A dan nilai B dari juri
pertama, lalu dari juri kedua, lalu dari juri ketiga.
Format keluaran. Satu baris berisi A,
B, atau SERI.
Batasan. Setiap nilai berada di antara 0 dan 100.
Contoh masukan
9 8 7 9 10 6
Contoh keluaran
A
Penjelasan. Juri pertama memilih A (9 > 8), juri kedua memilih B (9 > 7), juri ketiga memilih A (10 > 6). A mendapat dua suara, B satu suara.
Kerangkanya:
exercises/04/osn/03-juri-lomba.cpp
Bingung atau sudah selesai? Buka halaman pembahasan PR.