Uji Magic Square (Ed. 2) 1/9
Lecture Notes
Uji Magic Square Thompson Susabda Ngoen
Algoritma dan Pemrograman
Introduksi Magic square ialah suatu susunan bilangan mulai dari 1 sampai dengan n2 dalam sebuah tabel berukuran n x n, dan setiap bilangan muncul tepat satu kali, sedemikian rupa sehingga jumlah nilai bilangan-bilangan pada setiap baris, setiap kolom, dan setiap diagonal adalah sama.
Gambar 1. Magic Square Berukuran 3 dan 4
Kita akan menulis program untuk menguji apakah suatu susunan bilangan-bilangan merupakan magic square. Pada pembahasan ini ukuran magic square dibatasi maksimum 10. Data masukan diawali sebuah bilangan yang menyatakan ukuran magic square lalu diikuti bilangan-bilangan pembentuk magic square tersebut, seperti demikian: 3 8 1 6 3 5 7 4 9 2
Struktur Data Untuk menampung data magic square ini perlu disediakan sebuah larik dua dimensi dengan ukuran 10 x 10. Selain itu juga perlu disediakan variabel untuk untuk menampung: a) jumlah nilai masing-masing baris (10 buah), b) jumlah nilai masing-masing kolom (10 buah), c) jumlah nilai diagonal utama, dan d) jumlah nilai diagonal tambahan. Agar a, b, dan c dapat digabungkan ke dalam larik berukuran 10 x 10 tersebut maka gunakan larik berukuran 11 x 11.
Gambar 2. Array Penampung Data Magic Square
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 2/9
Urutan proses yang dilakukan adalah: a. inisialisasi dan membaca data magic square ke dalam array b. menghitung jumlah nilai masing-masing baris c. menghitung jumlah nilai masing-masing kolom d. menghitung jumlah nilai diagonal utama e. menghitung jumlah nilai diagonal tambahan f. menguji kesamaan jumlah nilai setiap baris, kolom, dan diagonal g. menguji keunikan masing-masing nilai
A. Inisialisasi dan Membaca Data Magic Square Magic square sebenarnya berbentuk bujur sangkar, artinya ukuran baris sama dengan kolom. Namun untuk memperjelas pembahasan kita menggunakan dua variabel, yaitu jbrs untuk menyatakan jumlah baris bujur sangkar dan jklm untuk menyatakan jumlah kolom bujur sangkar. Inisialisasi dilakukan dengan memberi nilai nol kepada jumlah nilai masingmasing baris, kolom, dan diagonal. Data masukan dibaca dengan menggunakan nested for( ). ª Inisialisasi
for (i = 0; i < 11; i++) { arr[i][10] = 0; arr[10][i] = 0; } diag_tambahan = 0;
ª Membaca data
scanf("%d", &jbrs); jklm = jbrs; for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) scanf("%d", &arr[i][j]);
B. Menghitung Jumlah Nilai Masing-Masing Baris Banyaknya baris data yang perlu diproses adalah sejumlah jbrs, atau dari 0 sampai dengan jbrs – 1, sehingga: for (i = 0; i <= jbrs - 1; i++) for (i = 0; i < jbrs; i++)
atau
Adapun elemen-elemen data yang dijumlahkan pada masing-masing baris diberikan Tabel 1 di bawah ini. Tabel 1. Penjumlahan Elemen-Elemen Sebaris Larik Elemen Larik yang Dijumlahkan Baris Ke-
1 2 3 …
arr[0][0], arr[0][1], arr[0][2] sampai dengan arr[0][jklm-1] arr[1][0], arr[1][1], arr[1][2] sampai dengan arr[1][jklm-1] arr[2][0], arr[2][1], arr[2][2] sampai dengan arr[2][jklm-1] …
Penampung Hasil
arr[0][10] arr[1][10] arr[2][10] …
Perhatikan bahwa indeks pertama penampung hasil penjumlahan adalah sama dengan indeks pertama elemen-elemen sebaris yang dijumlahkan, sedangkan indeks kedua penampung hasil penjumlahan selalu 10.
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 3/9
arr[0][0], arr[0][1], arr[0][2] s/d arr[0][jklm-1] dijumlahkan ke arr[0][10] arr[1][0], arr[1][1], arr[1][2] s/d arr[1][jklm-1] dijumlahkan ke arr[1][10] Dengan demikian penjumlahan bilangan-bilangan sebaris, misalnya baris dengan indeks i dapat ditulis sebagai: for (j = 0; j <= jklm - 1; j++) arr[i][10] = arr[i][10] + arr[i][j];
atau for (j = 0; j < jklm; j++) arr[i][10] = arr[i][10] + arr[i][j];
dan penjumlahan bilangan-bilangan untuk masing-masing baris dapat dituliskan sebagai: for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) arr[i][10] = arr[i][10] + arr[i][j];
C. Menghitung Jumlah Nilai Masing-Masing Kolom Banyaknya kolom data yang perlu diproses adalah sejumlah jklm, atau dari 0 sampai dengan jklm – 1, sehingga: for (i = 0; i <= jklm - 1; i++) atau for (i = 0; i < jklm; i++)
Adapun elemen-elemen yang dijumlahkan pada masing-masing kolom diberikan Tabel 2 di bawah ini. Tabel 2. Penjumlahan Elemen-Elemen Sekolom Larik Elemen Array Yang Dijumlahkan Kolom Ke1 2 3 …
arr[0][0], arr[1][0], arr[2][0] sampai dengan arr[jbrs-1][0] arr[0][1], arr[1][1], arr[2][1] sampai dengan arr[jbrs-1][1] arr[0][2], arr[1][2], arr[2][2] sampai dengan arr[jbrs-1][2] …
Penampung Hasil arr[10][0] arr[10][1] arr[10][2] …
Perhatikan bahwa indeks pertama penampung hasil penjumlahan selalu 10, sedangkan indeks kedua penampung hasil penjumlahan adalah sama dengan indeks kedua elemen-elemen yang dijumlahkan. arr[0][0], arr[1][0], arr[2][0] s/d arr[jbrs-1][0] dijumlahkan ke arr[10][0] arr[0][1], arr[1][1], arr[2][1] s/d arr[jbrs-1][1] dijumlahkan ke arr[10][1] Dengan demikian penjumlahan bilangan-bilangan sekolom, misalnya kolom dengan indeks i dapat ditulis sebagai: for (j = 0; j < jbrs; j++) arr[10][j] = arr[10][j] + arr[i][j];
dan penjumlahan bilangan-bilangan untuk masing-masing kolom dapat dituliskan sebagai for (i = 0; i < jklm; i++) for (j = 0; j < jbrs; j++) arr[10][j] = arr[10][j] + arr[i][j];
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 4/9
D. Menghitung Jumlah Nilai Diagonal Utama Elemen-elemen pembentuk diagonal utama adalah arr[0][0], arr[1][1], arr[2][2], arr[3][3] dan seterusnya, yaitu elemen-elemen yang indeks pertama dan dan indeks keduanya sama. Jumlah nilai elemen-elemen diagonal utama akan ditampung di arr[10][10]. Dengan menggunakan nested for() maka program menjadi: for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) if (i == j) arr[10][10] = arr[10][10] + arr[i][j];
atau dengan menggunakan satu instruksi for maka didapat: for (i = 0; i < jbrs; i++) arr[10][10] += arr[i][i];
E. Menghitung Jumlah Nilai Diagonal Tambahan Manakah elemen pembentuk diagonal tambahan? Perhatikan Gambar 3 dan Tabel 3 di bawah ini.
Gambar 3. Magic Square Berbagai Ukuran dan Elemen Diagonal Tambahan Tabel 3. Elemen Diagonal Tambahan Ukuran
2x2 3x3 4x4
Elemen Pembentuk Diagonal Tambahan
arr[0][1], arr[1][0] arr[0][2], arr[1][1], [2][0] arr[0][3], arr[1][2], arr[2][1], arr[3][0]
Indeks Pertama Perhatikan magic square berukuran 2 x 2. Elemen pertama pembentuk diagonal tambahan mempunyai indeks pertama bernilai 0. Elemen kedua pembentuk diagonal tambahan mempunyai Indeks pertama elemen bernilai 1. Perhatikan magic square berukuran 3 x 3. Elemen pertama pembentuk diagonal tambahan mempunyai Indeks pertama bernilai 0. Elemen keduanya berindeks pertama bernilai 1, dan elemen ketiganya berindeks pertama bernilai 2. Pada magic square berukuran 4 x 4 pola yang sama berlaku, yaitu indeks pertamanya dimulai dari 0, lalu 1, 2, dan 3; sehingga dapat disimpulkan bahwa untuk magic square berukuran n x n, indeks pertama bernilai 0, 1, 2, 3, dan seterusnya sampai dengan n – 1. Indeks Kedua Perhatikan magic square ukuran 2 x 2 pada Tabel 3. Indeks kedua elemen pertamanya bernilai 1. Indeks kedua elemen keduanya bernilai satu kurang dari nilai indeks kedua elemen pertama. 2 x 2 → arr[0][1], arr[1][0]
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 5/9
Perhatikan magic square ukuran 3 x 3 pada Tabel 3. Indeks kedua elemen pertamanya bernilai 2. Indeks kedua elemen-elemen selanjutnya bernilai satu kurang dari nilai indeks kedua elemen sebelumnya. 3 x 3 → arr[0][2], arr[1][1], arr[2][0] Demikian pula dengan magic square berukuran 4 x 4 yang indeks kedua elemen pertamanya bernilai 3, dan indeks kedua elemen-elemen berikutnya bernilai satu kurang dari nilai indeks kedua elemen sebelumnya. 4 x 4 → arr[0][3], arr[1][2], arr[2][ 1], arr[3][0] Dengan demikian dapat disimpulkan bahwa jika magic square berukuran n x n maka indeks keduanya bernilai mulai dari n – 1, lalu bernilai kurang-kurang satu, sampai dengan nol. Dengan menggabungkan ketentuan tentang indeks pertama dan ketentuan indeks kedua, yaitu: - indeks pertama bernilai 0, 1, 2, 3, dan seterusnya sampai dengan n-1 - indeks kedua bernilai n-1, n-2, n-3, dan seterusnya sampai dengan 0 Tabel 4. Indeks Pertama dan Kedua Elemen Diagonal Tambahan Elemen Ke
Indeks Pertama
Indeks Kedua
1 2 3 … n
[0] [1] [2] … [n-1]
[n-1] [n-2] [n-3] … 0
maka didapatkan relasi yaitu indeks kedua = n - indeks pertama - 1, dengan n berupa ukuran magic square. Dengan menggunakan variabel i untuk mengendalikan indeks pertama dan variabel j untuk mengendalikan indeks kedua maka program menjadi ª Jumlah nilai elemen diagonal tambahan
for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) if (j == jbrs – i – 1) diag_tambahan = daig_tambahan + arr[i][j];
ª atau dengan menggunakan satu instruksi for maka didapat:
for (i = 0; i < jbrs; i++) diag_tambahan = diag_tambahan + arr[i][jbrs – i - 1];
F. Menguji Kesamaan Jumlah Nilai Kita menggunakan sebuah variabel yang berfungsi sebagai switch, misalnya ms. Pada awalnya ms diberi nilai 1. Pada proses pengujian apabila ternyata jumlah nilai tidak sama maka nilai ms diubah menjadi 0. Pengujian kesamaan jumlah nilai baris dilakukan dengan membadingkan jumlah nilai baris ke-1 dengan jumlah nilai baris ke-2, jumlah nilai baris ke-1 dengan jumlah nilai baris ke-3 dan seterusnya.
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 6/9
ª Uji kesamaan jumlah nilai baris-baris ms = 1; for (i = 1; i < jbrs; i++) if (arr[i][10] != arr[0][10]) ms = 0;
Pengujian kesamaan jumlah nilai kolom dilakukan jika jumlah nilai baris adalah sama, yaitu jika variabel ms masih bernilai 1. Pengujian kesamaan jumlah nilai kolom dilakukan dengan membadingkan jumlah nilai kolom ke-1 dengan jumlah nilai kolom ke-2, jumlah nilai kolom ke-1 dengan jumlah nilai kolom ke-3, dan seterusnya ª Uji kesamaan jumlah nilai kolom-kolom if (ms == 1) for (i = 1; i < jklm; i++) if (arr[10][i] != arr[10][0]) ms = 0;
Pengujian kesamaan jumlah nilai diagonal dilakukan dengan membandingkannya dengan jumlah nilai lain, misalnya dengan jumlah nilai baris pertama. ª Uji kesamaan jumlah nilai diagonal if (ms == 1 && arr[10][10] != arr[0][10]) ms = 0; if (ms == 1 && diag_tambahan != arr[0][10]) ms = 0;
G. Menguji Keunikan Nilai Mengapa keunikan nilai masing-masing elemen magic square perlu diuji? Bukankah bila semua baris, semua kolom, dan kedua diagonal mempunyai jumlah nilai yang sama pasti menandakan bilangan-bilangan yang diuji membentuk magic square? Belum tentu. Apabila semua bilangannya bernilai sama maka semua jumlah nilai akan sama padahal bukan magic square. Pegujian keunikan nilai dilakukan apabila jumlah nilai semua baris, kolom, dan diagonal ternyata sama, yaitu variabel ms masih bernilai 1. Ketentuan lain mengenai magic square adalah bahwa masing-masing elemen harus bernilai antara 1 dan n x n (termasuk kedua nilai batas), dan semua nilai tersebut bersifat unik. Jadi terdapat dua ketentuan yang harus dipenuhi: 1. nilai setiap elemen tidak boleh lebih kecil dari 1 atau lebih besar daripada nxn 2. tidak boleh ada dua elemen atau lebih yang bernilai sama. Pengujian butir 1 mudah dilakukan. Pengujian butir 2 agak rumit. Misalnya magic square berukuran 3 x 3. Untuk menguji keunikan nilai elemen arr[0][1] maka harus membandingkan nilai elemen ini dengan dengan arr[0][0]. Untuk menguji keunikan nilai elemen arr[0][2] maka harus membandingkan nilai elemen ini dengan arr[0][0] dan arr[0][1]. Untuk menguji keunikan nilai elemen arr[2][2] maka harus membandingkan nilai elemen ini dengan semua elemen lainnya. Apakah ada cara lain yang lebih sederhana? Ada, dengan bantuan sebuah array lain untuk menampung nilai elemen yang sudah pernah muncul. Untuk menguji keunikan nilai ini kita memerlukan sebuah array satu dimensi yang mempunyai indeks [1] sampai dengan [n x n]. Pada pembahasan soal ini kita menggunakan array berlemen 101, misalnya diberi nama test. Pada mulanya
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 7/9
masing-masing elemen test [1] sampai dengan test[100] diberi nilai nol.
Gambar 4. Array test
Kemudian dilakukan penelusuran terhadap masing-masing elemen magic square. Jika elemen magic square bernilai 6 misalnya maka nilai test[6] ditambah 1.
Gambar 5. Mengubah Nilai Array test
Setelah semua elemen magic square selesai diprose, lakukan pemeriksaan terhadap test[1] sampai dengan test[n x n]. Jika masing-masing elemen ini bernilai 1 berarti masing-masing nilai muncul tepat satu kali. Jika terdapat test[a] yang bernilai > 1 berarti nilai a muncul lebih dari satu kali pada magic square. Jika terdapt test[b] yang bernilai 0 berarti nilai b tidak pernah muncul pada magic square. ª Inisialisasi array test for (i = 1; i <= jbrs * jbrs; i++) test[i] = 0
ª Mengisi array test for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) test[arr[i][j]]++;
ª Menguji keunikan nilai for (i = 1; i <= jbrs * jbrs; i++) if (test[i] != 1) { ms = 0; break; } Program 1. Uji Magic Square (A) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
# include <stdio.h> int main() { int arr[11][11], test[101], diag_tambahan, jbrs, jklm, i, j, ms; for (i = 0; i < 11; i++) { /*** bagian a ***/ arr[i][10] = 0; arr[10][i] = 0; } diag_tambahan = 0; scanf("%d", &jbrs); jklm = jbrs; for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) scanf("%d", &arr[i][j]);
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 8/9
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
for (i = 0; i < jbrs; i++) /*** bagian b ***/ for (j = 0; j < jklm; j++) arr[i][10] = arr[i][10] + arr[i][j]; for (i = 0; i < jklm; i++) /*** bagian c ***/ for (j = 0; j < jbrs; j++) arr[10][j] = arr[10][j] + arr[i][j]; for (i = 0; i < jbrs; i++) /*** bagian d ***/ for (j = 0; j < jklm; j++) if (i == j) arr[10][10] = arr[10][10] + arr[i][j]; diag_tambahan = 0; /*** bagian e ***/ for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) if (j == jbrs – i – 1) diag_tambahan = diag_tambahan + arr[i][j]; ms = 1; /*** bagian f ***/ for (i = 1; i < jbrs; i++) if (arr[i][10] != arr[0][10]) ms = 0; if (ms == 1) for (i = 1; i < jklm; i++) if (arr[10][i] != arr[10][0]) ms = 0; if (ms && arr[10][10] != arr[0][10]) ms = 0; if (ms && diag_tambahan != arr[0][10]) ms = 0; /*** bagian g, inisialisasi array test ***/ for (i = 1; i <= jbrs * jbrs; i++) test[i] = 0; /*** bagian g, mengisi array test ***/ for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) test[arr[i][j]]++; /*** bagian g, menguji keunikan nilai ***/ for (i = 1; i <= jbrs * jbrs; i++) if (test[i] != 1) { ms = 0; break; } if (ms == 1) printf("magic square"); else printf("bukan magic square"); return 0; }
Programnya cukup panjang. Apakah dapat dipersingkat ? Mari kita analisis program di atas. Bagian a untuk membaca data magic square (baris ke-14 s.d. ke-16) terdiri atas sebuah nested for. Bagian b (baris ke-18 s.d. ke-20) terdiri atas sebuah nested for. Bagian c (baris ke-22 s.d. ke-24) terdiri dari sebuah nested for. Bagian d (baris ke-26 s.d. ke-28) terdiri atas sebuah nested for. Bagian e (baris ke-31 s.d. ke-34) terdiri dari sebuah nested for. Bagian f mengisi larik test (baris ke-51 s.d. ke-53) juga terdiri atas sebuah nested for. Yang agak berbeda adalah bagian c yang instruksi for luar mempunyai kondisi i<jklm dan instruksi for dalam yang mempunyai kondisi j<jbrs. Tetapi karena jbrs bernilai sama dengan jklm maka kedua variabel ini dapat dipertukarkan. Dengan demikian keenam bagian ini bisa digabung. for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) {
INSTITUT BISNIS dan INFORMATIKA INDONESIA
Uji Magic Square (Ed. 2) 9/9
scanf("%d", &arr[i][j]); arr[i][10] = arr[i][10] + arr[i][j]; arr[10][j] = arr[10][j] + arr[i][j]; if (i == j) arr[10][10] = arr[10[10] if (j == jbrs – i – 1) diag_tambahan test[arr[i][j]]++; //***** f
//***** a //***** b //***** c + arr[i][j]; //***** d += arr[i][j]; //***** e
}
Bagian F yang melakukan pengujian jumlah nilai baris (baris ke-37 dan ke-38) dan pengujian jumlah nilai kolom (baris ke-41 dan ke-42) juga dapat digabung karena jbrs bernilai sama dengan jklm. ms = 1; for (i = 1; i < jbrs; i++) { if (arr[i][10] != arr[0][10]) ms = 0; if (arr[10][i] != arr[10][0]) ms = 0; }
Program 2. Uji Magic Square (B) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
# include <stdio.h> int main() { int arr[11][11], test[101], diag_tambahan, jbrs, jklm, i, j, ms; for (i = 0; i < 11; i++){ arr[i][10] = 0; arr[10][i] = 0; } diag_tambahan = 0; for (i = 0; i <= 100; i++) test[i] = 0; scanf("%d", &jbrs); jklm = jbrs; for (i = 0; i < jbrs; i++) for (j = 0; j < jklm; j++) { scanf("%d", &arr[i][j]); // a arr[i][10] += arr[i][j]; // b arr[10][j] += arr[i][j]; // c if (i == j) arr[10][10] += arr[i][j]; // d if (j == jbrs – i – 1) diag_tambahan += arr[i][j]; // e test[arr[i][j]]++; // f } ms = 1; for (i = 1; i < jbrs; i++) { if (arr[i][10] != arr[0][10]) ms = 0; if (arr[10][i] != arr[10][0]) ms = 0; } if (ms && arr[10][10] != arr[0][10]) ms = 0; if (ms && diag_tambahan != arr[0][10]) ms = 0; for (i = 1; i <= jbrs * jbrs; i++) if (test[i] != 1) ms = 0;
}
if (ms) printf("magic square"); else printf("bukan magic square"); return 0;
INSTITUT BISNIS dan INFORMATIKA INDONESIA