04. Percabangan — Pembahasan PR
Berkas .cpp jawabannya ada di
exercises/04/homework/solutions/.
Halaman ini dibuka sesudah mencoba sendiri. Bandingkan jalan pikiranmu dengan bagian Cara berpikir, bukan kodenya baris per baris: dua kode yang berbeda bentuk bisa sama-sama benar, dan yang perlu ditiru adalah cara sampai ke sana. Bagian Uji di tiap soal berisi masukan dan keluaran yang sudah diperiksa — jalankan jawabanmu sendiri dengan masukan itu sebelum merasa selesai.
Menjalankan salah satu jawabannya:
g++ -std=c++17 -O2 -o jawab exercises/04/homework/solutions/01-ganjil-genap.cpp
./jawab
Soal 1 — Ganjil atau genap
Soal. Baca satu bilangan bulat, cetak
genap atau ganjil, termasuk untuk bilangan
negatif.
Cara berpikir. n % 2 bernilai
0 untuk genap. Untuk bilangan negatif, C++ memberi
-1 (bukan 1) pada bilangan ganjil. Karena itu
memeriksa n % 2 == 0 aman, sedangkan memeriksa
n % 2 == 1 salah untuk -3.
Pembahasan.
int n;
cin >> n;
if (n % 2 == 0) cout << "genap\n";
else cout << "ganjil\n";Uji.
| Masukan | Keluaran |
|---|---|
4 |
genap |
7 |
ganjil |
0 |
genap |
-4 |
genap |
Kasus -4 itulah inti soalnya. Memeriksa
n % 2 == 0 aman untuk bilangan negatif, tetapi memeriksa
n % 2 == 1 untuk "ganjil" tidak:
-7 % 2 bernilai -1 di C++, bukan
1, sehingga -7 akan salah digolongkan genap.
Aman selalu: periksa == 0 dan taruh kasus ganjil di
else.
Kesalahan umum.
- Menulis
if (n % 2 == 1)lalu gagal pada masukan negatif. - Menulis
if (n = 2). Satu=mengisi nilai, dan kondisinya jadi selalu benar.
Soal 2 — Terbesar dari tiga
Soal. Cetak nilai terbesar dari tiga bilangan, tanpa
max.
Cara berpikir. Jangan mencoba menuliskan semua kemungkinan urutan — ada enam, dan kasus seri membuatnya makin berantakan. Pakai pola juara bertahan: anggap bilangan pertama yang terbesar, lalu tantang satu per satu. Pola ini nanti dipakai lagi untuk mencari nilai terbesar dalam array.
Kasus seri selesai dengan sendirinya karena pembandingnya
> (bukan >=): saat dua angka sama besar,
yang pertama bertahan dan hasil cetaknya tetap benar.
Pembahasan.
int besar = a;
if (b > besar) besar = b;
if (c > besar) besar = c;
cout << besar << "\n";Uji.
| Masukan | Keluaran |
|---|---|
3 9 5 |
9 |
7 7 7 |
7 |
-5 -2 -9 |
-2 |
Dua baris terakhir adalah kasus tepi yang diminta soal: nilai yang
sama besar tidak boleh membuat program gagal memilih, dan data yang
seluruhnya negatif tidak boleh dijawab 0.
Kesalahan umum.
- Menulis
if (a > b && a > c) ... else if (b > a && b > c) ...lalu lupa satu cabang, sehingga untuk masukan5 5 3tidak ada yang tercetak.
Soal 3 — Tahun kabisat
Soal. Cetak KABISAT atau
BUKAN.
Cara berpikir. Aturan "kecuali, kecuali lagi" lebih mudah ditulis sebagai satu ungkapan logika:
- habis dibagi 400 → pasti kabisat, atau
- habis dibagi 4 dan tidak habis dibagi 100.
Pembahasan.
bool kabisat = (tahun % 400 == 0) || (tahun % 4 == 0 && tahun % 100 != 0);
if (kabisat) cout << "KABISAT\n";
else cout << "BUKAN\n";Bentuk bertingkat di bawah ini juga benar, dan kadang lebih mudah dibaca:
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";Uji.
| Masukan | Keluaran | Alasannya |
|---|---|---|
2024 |
KABISAT |
habis dibagi 4, bukan kelipatan 100 |
2023 |
BUKAN |
tidak habis dibagi 4 |
1900 |
BUKAN |
kelipatan 100, bukan kelipatan 400 |
2000 |
KABISAT |
kelipatan 400 |
Keempat baris itu mewakili keempat cabang aturannya. Kalau salah satu saja tidak diuji, kesalahan urutan pemeriksaan bisa lolos tanpa terlihat.
Kesalahan umum.
- Hanya memeriksa
tahun % 4 == 0, sehingga 1900 dijawab kabisat. - Menaruh pemeriksaan
% 100sebelum% 400pada bentuk||, sehingga tahun 2000 dijawab bukan kabisat.
Soal 4 — Jenis segitiga
Soal. Tentukan apakah tiga sisi membentuk segitiga, lalu jenisnya.
Cara berpikir. Syarat segitiga: jumlah dua sisi
terpendek harus lebih besar dari sisi terpanjang.
Supaya tidak perlu memeriksa tiga pasangan, urutkan dulu ketiga nilainya
sehingga a <= b <= c; setelah itu satu pemeriksaan
a + b <= c sudah cukup.
Mengurutkan tiga nilai dengan tangan butuh tiga penukaran:
a–b, b–c, lalu
a–b sekali lagi.
Urutan pemeriksaan jenisnya juga penting: periksa sama sisi dulu, baru sama kaki. Kalau dibalik, segitiga sama sisi ikut terjaring sebagai sama kaki.
Pembahasan.
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";
}Uji.
| Masukan | Keluaran |
|---|---|
3 3 3 |
SAMA SISI |
5 5 8 |
SAMA KAKI |
3 4 5 |
SEMBARANG |
1 2 10 |
BUKAN SEGITIGA |
Urutan pemeriksaannya penting: syarat "bukan segitiga" harus
diperiksa lebih dulu. Kalau tidak, 1 2 10
akan dijawab SEMBARANG padahal ketiga sisi itu tidak bisa
membentuk segitiga sama sekali.
Kesalahan umum.
- Memakai
a + b < csebagai syarat gagal. Segitiga dengan sisi1 2 3tidak ada (ketiga titiknya segaris), jadi tandanya harus<=. - Lupa mengurutkan, lalu memeriksa hanya satu pasangan sisi.
- Memeriksa sama kaki sebelum sama sisi.
Tantangan — Harga tiket
Soal. Beberapa aturan diskon bisa berlaku bersamaan; ambil yang termurah.
Cara berpikir. Menyusun if / else if di
sini menyulitkan, karena else if akan berhenti di aturan
pertama yang cocok — padahal soal meminta yang termurah
di antara semua yang cocok. Pola yang tepat: simpan harga terbaik sejauh
ini, lalu periksa setiap aturan secara terpisah dan perbarui bila lebih
murah. Ini pola juara bertahan lagi, kali ini mencari yang terkecil.
Aturan umur < 5 dipisah di akhir karena nilainya
pasti nol dan mengalahkan semua.
Pembahasan.
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";Periksa dengan masukan 65 1: pelajar berumur 65. Aturan
pelajar memberi 40000, aturan lansia memberi 25000; jawabannya
25000.
Uji.
| Masukan | Keluaran | Aturan yang menang |
|---|---|---|
4 0 |
0 |
di bawah 5 tahun: gratis |
12 1 |
25000 |
5–17 tahun: setengah |
20 1 |
40000 |
pelajar dewasa: diskon 20% |
65 0 |
25000 |
60 tahun ke atas: setengah |
30 0 |
50000 |
tidak ada diskon |
Perhatikan baris 12 1: umur 12 dan berstatus pelajar
mengenai dua aturan sekaligus. Yang dipakai yang paling murah, yaitu
setengah harga, bukan diskon 20 persen.
Kesalahan umum.
- Memakai
else ifsehingga pelajar lansia tetap membayar 40000. - Menghitung diskon dengan
DASAR * 0.8lalu mencetaknya sebagaidouble, sehingga keluarannya40000.0dan ditolak penilai. Kalikan dulu baru bagi (DASAR * 80 / 100) agar tetap bilangan bulat.
Latihan bergaya OSN — pembahasan
Berkas jawabannya ada di
exercises/04/osn/solutions/.
Soal 1 — Tarif Parkir
Cara berpikir. Ada empat aturan, dan tiga di
antaranya saling mengesampingkan, jadi bentuknya rantai
if / else if / else. Urutannya mengikuti urutan aturan dari
yang paling khusus: durasi nol lebih dulu, lalu dua jam pertama, lalu
selebihnya.
Bagian yang perlu dipikirkan adalah "atau bagian dari jam". Kalimat
itu berarti pembulatan ke atas, dan pembulatan ke atas
untuk bilangan bulat ditulis (sisa + 59) / 60: menambah 59
membuat sisa berapa pun, sekecil apa pun, terdorong melewati kelipatan
60 berikutnya.
Batas atas 50000 bukan cabang tersendiri melainkan pemotongan di akhir, karena ia berlaku untuk hasil berapa pun.
Pembahasan.
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; // pembulatan ke atas
tarif = 5000 + 3000 * jam;
if (tarif > 50000) tarif = 50000;
}
cout << tarif << "\n";Uji.
| Masukan | Keluaran | Yang diperiksa |
|---|---|---|
480 480 |
0 |
durasi nol |
480 600 |
5000 |
tepat 120 menit, belum ada tambahan |
480 601 |
8000 |
satu menit lewat sudah dihitung sejam |
600 780 |
8000 |
tepat tiga jam |
0 1440 |
50000 |
tarif tertinggi |
Baris kedua dan ketiga adalah pasangan yang wajib diuji bersama: keduanya hanya berbeda satu menit, dan di situlah letak kesalahan yang paling sering.
Kesalahan umum.
- Memakai
sisa / 60, yang membulatkan ke bawah, sehingga 121 menit dihargai 5000. - Menuliskan batas 50000 sebagai cabang
else if, sehingga tidak berlaku pada perhitungan cabang lain. - Lupa memisahkan durasi nol, sehingga parkir nol menit dikenakan 5000.
Soal 2 — Jam Digital
Cara berpikir. Satu hari berisi 86400 detik. Karena
jam digital tidak menunjukkan tanggal, kelebihan harinya dibuang dengan
% 86400. Sesudah itu, pemecahannya adalah pasangan
/ dan % yang sama seperti memecah digit di Bab
03:
- jam:
hari / 3600 - menit:
(hari % 3600) / 60 - detik:
hari % 60
Bagian HH:MM:SS menuntut dua digit, jadi angka di bawah
10 perlu didahului 0. Karena setw dan
setfill belum dibahas, nol itu dicetak sendiri dengan
if.
Pembahasan.
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";Dengan <iomanip>, ketiga pasang baris itu bisa
diringkas menjadi
cout << setw(2) << setfill('0') << jam
dan seterusnya. Keduanya benar.
Uji.
| Masukan | Keluaran | Yang diperiksa |
|---|---|---|
0 |
00:00:00 |
semua bagian nol |
3661 |
01:01:01 |
contoh soal |
86399 |
23:59:59 |
detik terakhir dalam sehari |
86400 |
00:00:00 |
tepat satu hari penuh |
1000000000 |
01:46:40 |
T jauh di atas satu hari |
Kesalahan umum.
- Lupa
% 86400, sehinggaTbesar mencetak jam yang lebih dari 23. - Menghitung menit sebagai
hari / 60, bukan(hari % 3600) / 60. - Mencetak
1:1:1. FormatHH:MM:SSmenuntut dua digit di setiap bagian.
Soal 3 — Juri Lomba
Cara berpikir. Setiap juri diperiksa dengan pola
yang sama, sehingga ketiganya ditulis tiga kali dalam bentuk identik.
Perhatikan bahwa ada tiga kemungkinan per juri, bukan
dua: A menang, B menang, atau tidak ada yang dipilih. Karena itu
bentuknya if / else if tanpa else — kasus
ketiga memang tidak melakukan apa-apa.
Sesudah suara dihitung, perbandingan terakhirnya juga bertiga kemungkinan.
Pembahasan.
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";Uji.
| Masukan | Keluaran | Yang diperiksa |
|---|---|---|
9 8 7 9 10 6 |
A |
contoh soal |
1 2 3 3 4 5 |
B |
ada juri yang tidak memilih |
5 5 5 5 5 5 |
SERI |
tidak ada juri yang memilih |
Kasus ketiga penting: hasilnya seri bukan karena suaranya sama
banyak, melainkan karena tidak ada suara sama sekali. Jawaban yang hanya
membandingkan "siapa yang lebih banyak" tanpa cabang else
terakhir akan mencetak baris kosong di kasus ini.
Kesalahan umum.
- Memakai
elsepada pemeriksaan per juri, sehingga nilai sama dihitung sebagai kemenangan B. - Menjumlahkan nilai ketiga juri lalu membandingkan totalnya. Itu soal
yang berbeda: peserta bisa menang total nilai tetapi kalah suara juri,
seperti pada
1 10 5 4 5 4. - Mencetak
Seriatauseri. Soal memintaSERI.
Kalau masih tersendat
- Rantai
ifmemilih cabang yang salah → Bab 04, tabel penelusuran pada bagianif,else if,else. - Menerjemahkan kalimat soal menjadi syarat → Bab 04, bagian Menerjemahkan kalimat soal menjadi kondisi.
- Menggabungkan beberapa syarat → Bab 04, bagian Menggabungkan kondisi dan tabel kebenarannya.
Sebelum lanjut ke Bab 05, pastikan kamu bisa menulis syarat untuk
"umurnya antara 5 dan 17 tahun" beserta kebalikannya, tanpa ragu pada
tanda < dan <=.