Category Archive: Algoritma dan Pemrograman

Jan 17 2012

Pengurutan (Sorting) Multi Kolom dengan Java

Pengurutan merupakan sesuatu yang umum dan sering diperlukan. Saat belajar algoritma dan pemrograman, topik pengurutan biasanya selalu ada. Masalah pengurutan ini juga sering muncul dalam programming, baik itu dalam programming ilmu komputer (seperti soal-soal ICPC, TopCoder, dll) maupun dalam programming dunia industri.

Andaikan kita seorang software developer yang sedang mengerjakan proyek web sepak bola. Dalam web tersebut, kita akan menampilkan klasmen suatu liga. Nah, buat yang belum mengerti apa itu klasmen, begini penjelasannya.

Klasmen merupakan tabel berisi data hasil pertandingan. Hasil pertandingan yang dimaksud adalah:

  • jumlah pertandingan yang sudah dijalani (Wins + Draws + Loses [lihat 3 item selanjutnya!])
  • jumlah pertandingan yang berakhir dengan dimenangkan (Wins, disingkat menjadi W)
  • jumlah pertandingan yang berakhir seri (Draws, disingkat menjadi D)
  • jumlah pertandingan yang berakhir dengan kekalahan (Loses, disingkat menjadi L)
  • jumlah gol ke gawang lawan (Goals For, disingkat menjadi GF)
  • jumlah gol ke gawang sendiri (Goals Against, disingkat menjadi GA)
  • selisih gol (Goals Difference, disingkat menjadi GD, yaitu GF – GA)
  • poin (Points, disingkat menjadi Pts, yaitu 3 * W + D)

Klasmen disusun berdasarkan poin. Tim yang memiliki poin lebih besar akan berada di atas, demikian sebaliknya. Jika poin kedua sama, diurutkan berdasarkan selisih gol. Tim yang memiliki selisih gol lebih besar akan berada di atas, demikian sebaliknya.

Perhatikan data hasil pertandingan (pertengahan Januari 2012) dari enam klub English Premier League berikut:

Klub/Tim             Wins  Draws  Loses  Goals-For  Goals-Against
-----------------------------------------------------------------
Arsenal              11    3      6      36         28
Chelsea              12    4      5      40         25
Liverpool            9     8      4      24         18
Manchester City      15    3      2      56         16
Manchester United    15    3      3      52         20
Tottenham Hotspur    14    4      3      39         21

Tabel di atas masih berisi data mentah dan belum diurutkan (urutan sementara berdasarkan nama klub). Untuk mengurutkannya, kita harus menghitung poin dan selisih goal, sebagai berikut:

Klub                 W   D  L  GF  GA  Pts(1)  GD(2)
----------------------------------------------------
Arsenal              11  3  6  36  28  36      8
Chelsea              12  4  5  40  25  40      15
Liverpool            9   8  4  24  18  35      6
Manchester City      15  3  2  56  16  48      40
Manchester United    15  3  3  52  20  48      32
Tottenham Hotspur    14  4  3  39  21  46      18

Keterangan
(1) Pts = points = poin
(2) GD = goals difference = selisih gol

Maka klasmen akan diperoleh sebagai berikut:

Klub                 W   D  L  GF  GA  Pts  GD
----------------------------------------------
Manchester City      15  3  2  56  16  48   40
Manchester United    15  3  3  52  20  48   32
Tottenham Hotspur    14  4  3  39  21  46   18
Chelsea              12  4  5  40  25  40   15
Arsenal              11  3  6  36  28  36   8
Liverpool            9   8  4  24  18  35   6

Perhatikan bahwa data sekarang telah diurut berdasarkan poin (Pts) dan selisih gol (GD). Ada dua klub yang memiliki poin sama, yaitu Manchester City dan Manchester United. Tetapi, karena selisih gol Manchester City lebih besar, klub tersebut berada di atas.

Sekarang, anggap data hasil pertandingan tersebut disimpan di tabel tbl_klasmen dalam database. Tabel tersebut memiliki struktur seperti ini:

Field            Type
------------------------
team_name        VARCHAR
wins             INTEGER
draws            INTEGER
loses            INTEGER
goals_for        INTEGER
goals_against    INTEGER

Dan berisi enam data seperti yang diperlihatkan pada tabel pertama di atas.

Jika menggunakan query SQL, maka untuk mendapatkan klasmen akan semudah ini:

SELECT *, (3 * wins + draws) AS points, (goals_for - goals_against) AS goals_difference
  FROM `tbl_klasmen`
  ORDER BY points DESC, goals_difference DESC;

Masalah selesai.

Bagaimana kalau datanya tidak berasal dari tabel database?

Read the rest of this entry »

  • Facebook
  • Twitter
  • Delicious
  • Digg
  • Google Buzz
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Permanent link to this article: http://www.muhammadalvin.net/2012/01/pengurutan-multi-kolom-dengan-java/

Jan 02 2012

Kalender Maya

Pagi ini, 2 Januari 2012, jalanan begitu sunyi. Sepertinya banyak yang cuti bersama. Mungkin karena itu juga, saya tiba di kantor terlalu awal, sebelum jam 8.00. Masih terlalu pagi, jadi saya buka-buka twitter, lihat-lihat timeline, ketemu beberapa twit berita yang cukup menarik. Salah satunya tentang isu kiamat di Desember 2012 (yang katanya sebagai efek dari berakhirnya sistem penanggalan pada kalender suku Maya) yang ditolak oleh suku Maya sendiri. Ada seorang peneliti yang cukup mengerti dengan suku Maya. Menurut informasi yang ia peroleh, suku Maya sendiri tidak pernah memprediksi itu. Memang benar salah satu siklus penanggalan akan berakhir di Desember 2012, tetapi itu hanyalah merupakan akhir dari siklus penanggalan, bukan akhir dunia. Setelah akhir itu, akan ada siklus penanggalan berikutnya. Dan katanya, ini bukan yang pertama terjadi. Apapun itu, sebagai muslim, saya tetap percaya bahwa datangnya kiamat tidak akan ada yang tahu, selain Allah SWT.

Seperti biasa, keingintahunan saya mendadak muncul. Saya googling tentang sistem penanggalan suku Maya tersebut. Tentu saja saya mendapatkan artikel dari Wikipedia tentang itu. Tetapi yang membuat saya tertarik adalah ini:

http://livearchive.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=459&page=show_problem&problem=3516

Setelah membaca dan melihat batasan soal tersebut, saya berpikir ini soal yang cukup mudah. Soal ini tidak butuh algoritma-algoritma rumit untuk menyelesaikannya.

Jenis soal: ad-hoc

Analisis: Sistem penanggalan Haab memiliki 365 hari dalam setahun, dengan batasan tahun adalah 5000. Itu berarti total hari sejak hari pertama sampai hari terakhir masih kurang dari 2 juta. Bukan angka yang besar, dan tipe data integer (32 bit) masih memiliki banyak tempat untuk itu.

Oke, mari kita coding!

Awalnya mau pakai Java, tetapi karena belum pernah submit dengan Java di LiveArchive, saya pilih bahasa yang dulu sering saya gunakan, C++.

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;

int main()
{
    string haab[19] = { "pop", "no", "zip", "zotz", "tzec", "xul", "yoxkin",
        "mol", "chen", "yax", "zac", "ceh", "mac", "kankin", "muan", "pax",
        "koyab", "cumhu", "uayet" };    
    string tzolkin[20] = { "imix", "ik", "akbal", "kan", "chicchan", "cimi",
        "manik", "lamat", "muluk", "ok", "chuen",  "eb", "ben", "ix", "mem",
        "cib", "caban", "eznab", "canac", "ahau" };

    int nTC; cin >> nTC; cin.ignore();
    cout << nTC << endl; // output-nya butuh ini!
    string input;
    while (nTC-- > 0) {
        getline(cin, input);

        int d = 0;
        string m = "";
        int y = 0;

        int flag = 1;
        for (int i = 0, n = input.size(); i < n; i++) {
            char c = input[i];
            if (c == '.') {
                flag = 2;
            } else if (c == ' ' && flag == 2) {
                flag = 3;
            } else if (c == ' ' && flag == 3) {
                flag = 4;
            } else if (flag == 1) {
                d *= 10; d += c - '0';
            } else if (flag == 3) {
                m += c;
            } else if (flag == 4) {
                y *= 10; y += c - '0';
            }
        }

        int indeksBulan = -1;
        for (int i = 0; i < 19; i++) {
            if (haab[i] == m) {
                indeksBulan = i;
                break;
            }
        }

        unsigned int jumlahHari = (y * 365) + (20 * indeksBulan) + d;
        // cout << jumlahHari << endl;

        unsigned tahunTzolkin = jumlahHari / 260;
        unsigned sisa = jumlahHari % 260;

        int a = 0, b = 0;
        for (int i = 0; i < sisa; i++) {
            a = (a + 1) % 13;
            b = (b + 1) % 20;
        }

        cout << (a + 1) << " " << tzolkin[b] << " " << tahunTzolkin << endl;
    }

    // system("pause");
}

Array haab dan tzolkin tidak diketik satu persatu itemnya. Ada cara cepat dengan bantuan Notepad++ dan regular expression.

Cara memparsing input nya juga cukup ‘bodoh’ :D . Tapi that’s OK lah, itu gak jadi persoalan. Hasil parsing adalah mengisi 3 variabel berikut:

  • d = tanggal di kalendar Haab (input), dimulai dari 0.
  • m = bulan di kalender Haab (input).
  • y = tahun di kalender Haab (input), dimulai dari 0.

Langkah pertama: Kalender Haab terdiri dari 365 hari dalam setahun. Jika y = 0, maka tanggal tersebut belum setahun. Jika y = 1, maka tanggal tersebut sudah lebih setahun. Jika y = 2, maka tanggal tersebut sudah lebih 2 tahun. Artinya, berapapun nilai y, tanggal tersebut sudah melebihi y tahun, atau y * 365 hari.

Langkah kedua: Kalender Haab terdiri dari 19 bulan. 18 bulan pertama (pop s.d. cumhu) memiliki 20 hari, dan bulan terakhir (uayet) memiliki 5 hari. Suatu tanggal di bulan pertama, berarti tanggal tersebut belum sebulan pada tahun tersebut. Suatu tanggal di bulan kedua, berarti tanggal tersebut sudah lebih 1 bulan pada tahun tersebut. Suatu tanggal di bulan ketiga, berarti tanggal tersebut sudah lebih 2 bulan pada tahun tersebut. Dan seterusnya sampai suatu tanggal di bulan ke-19, berarti tanggal tersebut sudah lebih 18 bulan pada tahun tersebut. Nah, karena kebetulan bulan pertama sampai bulan ke-18 terdiri dari 20 hari, maka kalikan saja dengan 20 berapa bulan yg sudah dilewati.

Langkah ketiga: Tambahkan angka tanggal.

Hasil akhirnya begini:

jumlahHari = (y * 365) + (20 * indeksBulan) + d;

indeksBulan = 0 untuk bulan pertama (pop), 1 untuk bulan kedua (no), 2 untuk bulan ketiga (zip), dst.

Sebenarnya ini nggak begitu pas. Kenapa? Coba perhatikan tanggal 0. pop 0 yang merupakan tanggal pertama di kalender Haab. Menggunakan rumus di atas, maka:

jumlahHari = (0 * 365) + (20 * 0) + 0 = 0

Hari pertama, kenapa 0? Bukannya 1? Ya pertanyaan bagus. Jawabannya adalah karena kita akan menghitung dari 0, bukan 1. Ini akan memudahkan kita dalam baris kode selanjutnya jika dibandingkan dengan menghitung dari 1.

Kalender Tzolkin memiliki 13 periode dan 20 hari. Berdasarkan permutasi yang dicontohkan di soal, kita bisa mengetahui bahwa ada maksimum 13 * 20 hari = 260 hari di kalender Tzolkin.

1 hari di kalender Haab berarti 1 hari (kurang dari setahun) di kalender Tzolkin, 2 hari di kalender Haab berarti 2 hari (kurang dari setahun) di kalender Tzolkin, …, 260 hari di kalender Haab berarti 1 tahun di kalender Tzolkin, 261 hari di kalender Haab berarti 1 tahun lebih 1 hari di kalender Tzolkin, dst. Dengan kata lain, 1 hari sampai dengan 260 hari belum melewati setahui kalender Tzolkin. Karena kita menghitung dari 0, maka berapa tahun di kalender Tzolkin yang sudah dilewati dapat dengan mudah diperoleh dengan membaginya dengan 260 lalu mengambil bagian integernya. 0 / 260 = 0; 1 / 260 = 0; 259 / 260 = 0. Akan sedikit lebih sulit jika menghitung dari 1, karena 260 / 260 = 1, padahal 260 hari belum melewati setahun tahun Tzolkin.

Setelah mendapatkan berapa tahun Tzolkin, hitung sisanya dengan jumlahHari % 260. Tentukan tanggal dan bulan apa yang tepat dari sisa tersebut. Di sini lagi-lagi saya menghitung dari 0. Ini sangat membantu, karena ada operasi modulo dan penggunaan array (indeks array juga dimulai dari 0).

Saat menampilkan, pastikan untuk menambahkan tanggal dengan 1, karena tanggal pertama di kalender Tzolkin adalah 1, bukan 0.

———-

Mestinya soal ini Accepted dalam submission pertama, tetapi gara2 tidak teliti membaca apa yang diminta di output, jadi Wrong Answer beberapa kali. Masalahnya sepele: baris pertama output adalah banyaknya output, yang nilainya sama dengan jumlah test case. Setelah itu, barulah output.

Yang lebih parahnya lagi, hal tersebut lama disadari. Bahkan sampai mencoba hal-hal ini:

if (d >= 20) {
    cout << 1/0; // pembagian dengan 0 untuk memancing Runtime Error
}

Karena di soal nggak dijelaskan kalau input-an pasti valid, maka’a sampai repot-repot ngecek itu. Dan ternyata setelah di-submit, memang benar nggak Runtime Error, karena input-an nya valid.

Akhirnya setelah disadari, 1 baris berikut ditambahkan:

cout << nTC << endl;

Dan hasil submit-pun berubah menjadi Accepted. Tanpamu, semua itu tak berarti! Tanpa baris tersebut, semua jawaban yang sudah benar tetap sia-sia.

  • Facebook
  • Twitter
  • Delicious
  • Digg
  • Google Buzz
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Permanent link to this article: http://www.muhammadalvin.net/2012/01/kalender-maya/

Nov 28 2011

Mengurutkan Bilangan dengan Selection Sort

Untuk mengurutkan sekumpulan bilangan, dapat dilakukan dengan berbagai cara (algoritma), misalnya bubble sort, selection sort, merge sort, quick sort. Di bawah ini akan dijelaskan cara mengurutkan sekumpulan bilangan menggunakan selection sort.

Dalam selection sort ini kita memilih (select) bilangan terkecil, kemudian menempatkannya di awal. Kemudian memilih bilangan terkecil selanjutnya (terkecil kedua), dan menempatkannya di posisi setelah awal (posisi kedua). Berikutnya memilih bilangan terkecil ketiga, dan menempatkannya di posisi ketiga. Begitu seterusnya.

Misalnya diberikan sekumpulan bilangan berikut:

 3   8   5   7   2   3   6   8   0   4

Maka cara mengurutkannya seperti ini.

Pertama, cari bilangan yang paling kecil dari paling kiri (posisi 1):

 3   8   5   7   2   3   6   8   0   4
 --------------------------------|

Pindahkan bilangan tersebut ke depan (posisi 1). Bilangan yang ada di posisi 1 tersebut dipindahkan ke posisi bilangan terkecil tadi (istilahnya swap = tukar tempat):

[0]  8   5   7   2   3   6   8  [3]  4

Maka posisi 1 sudah berisi bilangan yang tepat.

Selanjutnya, cari bilangan yang paling kecil berikutnya. Kali ini, tidak dari posisi 1 (karena di posisi tersebut sudah berisi bilangan yang tepat), tetapi cari dari posisi 2:

 0   8   5   7   2   3   6   8   3   4
     ------------|

Swap bilangan tersebut ke posisi 2:

 0  [2]  5   7  [8]  3   6   8   3   4

Maka posisi 2 sudah berisi bilangan yang tepat.

Selanjutnya, cari bilangan yang paling kecil berikutnya. Kali ini, dari posisi 3:

 0   2   5   7   8   3   6   8   3   4
         ------------|

Swap bilangan tersebut ke posisi 3:

 0   2  [3]  7   8  [5]  6   8   3   4

Maka posisi 3 sudah berisi bilangan yang tepat.

Selanjutnya cari bilangan yang paling kecil berikutnya dari posisi 4:

 0   2   3   7   8   5   6   8   3   4
             --------------------|

Kemudian swap:

 0   2   3  [3]  8   5   6   8  [7]  4

Selanjutnya dari posisi 5:

 0   2   3   3   8   5   6   8   7   4
                 --------------------|

Hasil swap:

 0   2   3   3  [4]  5   6   8   7  [8]

Selanjutnya dari posisi 6:

 0   2   3   3   4   5   6   8   9   8
                     |

Karena bilangan terkecil berikutnya sudah terletak di posisinya yang sesuai, maka tidak perlu dilakukan swap.

Selanjutnya dari posisi 7:

 0   2   3   3   4   5   6   8   9   8
                         |

Ini juga tidak perlu melakukan swap.

Selanjutnya dari posisi 8:

 0   2   3   3   4   5   6   8   9   8
                             |

Tidak perlu swap.

Selanjutnya dari posisi 9 yang merupakan posisi terakhir. Setelah mencari bilangan terkecil dari posisi ini dan melakukan swap, kita tidak perlu melanjutkan pencarian ke posisi 10. Pada posisi tersebut sudah pasti berisi bilangan terbesar yang merupakan hasil swap-swap sebelumnya.

 0   2   3   3   4   5   6   8   9   8
                                 ----|

Hasil swap terakhir (hasil ini sudah terurut):

 0   2   3   3   4   5   6   8  [8] [9]

Berikut adalah contoh implementasi algoritma di atas dalam bahasa C++:

#include <iostream>
#include <cstdlib>
using namespace std;

int main()
{
    int N;
    cout << "N = ";
    cin >> N;

    int bilangan[N];
    cout << "bilangan (pisah dgn spasi) = ";
    for (int i = 0; i < N; i++) {
        cin >> bilangan[i];
    }

    // selection sort
    for (int i = 0; i < N - 1; i++) {
        // cari yg paling minimum
        int posisiTerkecil = i;
        for (int j = i + 1; j < N; j++) {
            if (bilangan[j] < bilangan[posisiTerkecil]) {
                posisiTerkecil = j;
            }
        }

        // swap ke depan (kalo memang perlu dilakukan swap)
        if (posisiTerkecil != i) {
            int sementara = bilangan[i];
            bilangan[i] = bilangan[posisiTerkecil];
            bilangan[posisiTerkecil] = sementara;
        }
    }

    cout << "hasil = ";
    for (int i = 0; i < N; i++) {
        cout << bilangan[i] << " ";
    }

    cout << endl;

    // system("pause");
}

Dan berikut merupakan contoh implementasi dalam Java:

import java.util.Scanner;

public class SelectionSort {

    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);

        System.out.print("N = ");
        int N = sc.nextInt();

        System.out.print("bilangan (pisah dgn spasi) = ");
        int[] bilangan = new int[N];
        for (int i = 0; i < N; i++) {
            bilangan[i] = sc.nextInt();
        }

        // selection sort
        for (int i = 0; i < N - 1; i++) {
            // cari bilangan terkecil
            int posisiTerkecil = i;
            for (int j = i + 1; j < N; j++) {
                if (bilangan[j] < bilangan[posisiTerkecil]) {
                    posisiTerkecil = j;
                }
            }

            // swap (jika memang harus di-swap)
            if (posisiTerkecil != i) {
                int sementara = bilangan[i];
                bilangan[i] = bilangan[posisiTerkecil];
                bilangan[posisiTerkecil] = sementara;
            }
        }

        System.out.print("hasil = ");
        for (int i = 0; i < N; i++) {
            System.out.print(bilangan[i] + " ");
        }
        System.out.println();
    }

}

  • Facebook
  • Twitter
  • Delicious
  • Digg
  • Google Buzz
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Permanent link to this article: http://www.muhammadalvin.net/2011/11/mengurutkan-bilangan-dengan-selection-sort/

Nov 26 2011

Artechno Festival Programming Competition – Monyet dan Pisang (H)

Saya mendapatkan ide soal ini dari soal ACORN untuk ACM/ICPC Asia Regional Contest 2007 Singapore. Ketika itu, USU mengirimkan dua tim untuk acara ini. Tim pertama terdiri dari saya, Alfarisi, Surya Wijaya, dan tim kedua terdiri dari Izhari Ishak Aksa, Ronny Silitonga, Jefri Umar (sebenarnya tim kami yang merupakan tim kedua :D ). Tim kami tidak berhasil menyelesaikan soal tersebut, sementara tim satunya berhasil. Setelah kembali ke tanah air, saya berhasil menyelesaikannya. Kegagalan ini membuat saya selalu teringat dengan soal tersebut. Pelajaran berharga memang dari pengalaman, pengalaman adalah guru terbaik. Begitu kata teman saya – Yayan – ketika saya berbagi pengalaman ini.

Alice dan Bob merupakan peneliti yang sedang melakukan percobaan mutasi gen. Alice melakukan percobaannya terhadap pohon pisang, sehingga beberapa pohon pisang dapat tumbuh dengan ketinggian yang sama dan memiliki buah di berbagai titik di sepanjang pohon tersebut. Sementara Bob melakukan percobaannya terhadap monyet, sehingga monyet tersebut dapat menyelesaikan permasalahan dengan algoritma tertentu.

Alice dan Bob tinggal bersebelahan. Rumah keduanya memiliki halaman yang hanya terpisah dinding yang cukup tinggi. Di halaman rumah itulah keduanya melakukan percobaannya. Suatu hari, seekor monyet dari halaman rumah Bob secara tidak sengaja memanjat dinding tersebut dan melihat beberapa pohon pisang yang ada di rumah Alice. Melihat banyaknya pisang yang tersebar di pohon-pohon tersebut, monyet tersebut tergoda untuk mengambilnya.

Dari atas dinding, monyet hanya bisa melompat ke salah satu pohon. Selanjutnya ia harus menuruni pohon tersebut sambil mengambil pisang yang dilewatinya. Saat menuruni pohon, ia bisa turun lurus ke bawah sejauh 1 meter atau pindah ke pohon tepat di sebelah kiri atau kanannya sambil turun sejauh 2 meter.

Tentukan berapa jumlah pisang terbanyak yang dapat diambil oleh monyet tersebut.

Sebagai contoh, Alice memiliki 3 pohon pisang dengan ketinggian 5 meter. Pohon pertama memiliki 5 pisang di ketinggian 2 meter, 15 pisang di ketinggian 4 meter, dan 5 pisang di ketinggian 5 meter. Pohon kedua memiliki 20 pisang di ketinggian 2 dan 3 meter. Pohon ketiga memiliki 15 pisang di ketinggian 4 meter. Jika digambarkan menjadi seperti berikut:

Jika monyet memilih pohon pertama lalu turun lurus ke bawah, maka ia akan memperoleh 5 + 15 + 5 = 25 pisang. Jika memilih pohon kedua lalu turun lurus ke bawah, maka ia akan memperoleh 20 + 20 = 40 pisang. Jika memilih pohon ketiga lalu turun lurus ke bawah, maka ia akan memperoleh 15 pisang.

Jika monyet memilih pohon pertama lalu turun ke ketinggian 4 meter di pohon yang sama, kemudian pindah ke pohon kedua ke ketinggian 2 meter, maka ia akan memperoleh 5 + 15 + 20 = 40 pisang.

Tetapi jika monyet memilih pohon pertama, lalu pindah ke pohon kedua ke ketinggian 3 meter, kemudian turun terus ke bawah, maka ia akan memperoleh 5 + 20 + 20 = 45 pisang. Pada test case ini, 45 pisang adalah jumlah maksimum yang dapat diambil.

Ingat: Pindah pohon berarti turun 2 meter, dan monyet hanya bisa pindah ke pohon yang berada tepat di sebelah kiri atau kananya. Sebagai contoh, jika ada empat pohon dan monyet berada di pohon kedua, maka ia bisa pindah ke pohon pertama atau ketiga, tetapi tidak bisa pindah ke pohon keempat.

Input:
Input diawali oleh T (1 <= T <=1000) yang menunjukkan jumlah test case.

Setiap test case terdiri dari beberapa baris. Baris pertama berisi dua buah bilangan bulat N dan H (1 <= N, H <= 50), di mana N merupakan banyaknya pohon pisang setinggi H meter yang terdapat di halaman Alice. N baris berikutnya berisi H buah integer (X1 X2 X3 … XH di mana 0 <= Xi <= 100) yang menunjukkan letak dan jumlah pisang di setiap pohon. Integer pertama (X1) adalah jumlah pisang di ketinggian 1 meter, integer kedua (X2) adalah jumlah pisang di ketinggian 2 meter, integer ketiga (X3) adalah jumlah pisang di ketinggian 3 meter, dst.

Output:
Untik setiap test case, tampilkan jumlah maksimum pisang yang dapat diambil untuk test case tersebut.

Contoh input:
4
3 5
0 5 0 15 5
0 20 20 0 0
0 0 0 15 0
1 1
10
1 10
0 0 0 0 0 0 0 0 0 0
2 5
1 2 3 4 5
1 2 3 4 5

Contoh output:
45
10
0
15

———-

Cara penyelesaian soal ini mirip seperti soal Rute Maksimal (B). Jika pada soal tersebut, yang kita cari adalah maksimum untuk turun ke kiri atau ke kanan, maka pada soal ini yang kita cari adalah maksimum untuk:

  • turun lurus (1 langkah ke bawah)
  • turun ke kiri (2 langkah ke bawah)
  • turun ke kanan (2 langkah ke bawah)

Berikut ini merupakan contoh solusi dalam bahasa Java:

import java.util.Scanner;
import java.util.Arrays;

public class H {

    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);

        int nTC = sc.nextInt();
        while (nTC-- > 0) {
            int N = sc.nextInt();
            int H = sc.nextInt();

            int[][] pohon = new int[52][52]; // batasan pada soal: 1 <= N, H <= 50
            for (int i = 0; i <= N; i++) {
                Arrays.fill(pohon[i], 0);
            }

            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= H; j++) {
                    pohon[i][j] = sc.nextInt();
                }
            }

            int hasil = 0; // terbanyak di ketinggian H

            // mulai dari baris ke-2 dari bawah sampai paling atas
            for (int i = 2; i <= H; i++) {
                for (int j = 1; j <= N; j++) {
                    // cari turun yg optimmal!
                    int best = pohon[j][i] + pohon[j][i - 1]; // turun lurus
                    if (j - 1 >= 1 && i - 2 >= 1) {
                        best = Math.max(best, pohon[j][i] + pohon[j - 1][i - 2]); // turun ke kiri
                    }
                    if (j + 1 <= N && i - 2 >= 1) {
                        best = Math.max(best, pohon[j][i] + pohon[j + 1][i - 2]); // turun ke kanan
                    }

                    pohon[j][i] = best; // update!

                    if (i == H) {
                        hasil = Math.max(hasil, pohon[j][i]); // update hasil
                    }
                }
            }

            System.out.println(hasil);
        }
    }

}

Input dan output yang digunakan oleh juri bisa dilihat di sini.

———-

Untuk soal ACORN, karena time limit untuk soalnya hanya 3 detik, maka tidak bisa menggunakan looping 3 tingkat (pertama untuk mengiterasi setiap ketinggian, kedua untuk mengiterasi setiap pohon, ketiga untuk mengiterasi arah turun). Saya sudah mencoba solusi tersebut dan dinyatakan No – Time Limit Exceeded. Agar mendapatkan Yes/Accepted, harus menggunakan teknik dynamic programming, di mana kita menyimpan maksimum dari tiap-tiap ketinggian di tabel DP (ada juga yang menyebutnya tabel memo). Ini akan meng-eliminasi looping ketiga dengan cara melihat nilai maksimum untuk ketinggian tertentu ke tabel DP tersebut.

  • Facebook
  • Twitter
  • Delicious
  • Digg
  • Google Buzz
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Permanent link to this article: http://www.muhammadalvin.net/2011/11/artechno-festival-programming-competition-monyet-dan-pisang/

Nov 26 2011

Artechno Festival Programming Competition – Hitung Prima (G)

Soal dibuat oleh Izhari Ishak Aksa.

Diberikan sebuah deretan bilangan bulat, jumlahkan bilangan-bilangan pada deretan tersebut yang merupakan bilangan prima (bilangan yang pembaginya hanya 1 dan bilangan itu sendiri). Tentukan pada bilangan prima ke berapa pada deretan tersebut ketika hasil penjumlahannya melebihi 100. Asumsikan bahwa untuk setiap kasus, pasti akan terdapat jawaban untuk hasil penjumlahan melebihi 100.

Input:
Input diawali oleh T (1 <= T <= 1000) yakni banyaknya test case.
Untuk setiap test case, diawali bilangan bulat N yang menunjukkan banyaknya bilangan pada deretan bilangan bulat. N baris berikutnya, berisi bilangan bulat X (0 < X < 1000) yaitu bilangan bulat yang dimaksud dalam deretan tersebut.

Output:
Untuk setiap test case, tampilkan sebuah bilangan bulat yang menunjukkan bilangan prima ke berapa saat hasil penjumlahannya melebihi 100.

Contoh input:
2
6
10
7
41
32
43
17
2
9
101

Contoh output:
4
1

Catatan:
Contoh input baris ke-8 tertulis 2, seharusnya 17.

———-

Pada soal ini, diminta menjumlahkan setiap bilangan prima yang ditemukan. Saat penjumlahan tersebut menghasilkan jumlah yang lebih besar dari 100, maka hentikan penjumlahan dan tampilkan pada penjumlahan ke berapa yang menghasilkan jumlah lebih dari 100 tersebut.

Berikut ini merupakan contoh solusi menggunakan bahasa Java:

import java.util.Scanner;
import java.util.Arrays;

public class G {

    public static void main(String[] args)
    {
        Scanner sc = new Scanner(System.in);

        // sieve of eratosthenes
        boolean[] prima = new boolean[1002]; // batasan input: 0 < X < 1000
        Arrays.fill(prima, true);
        prima[0] = prima[1] = false;
        for (int i = 2; i * i <= 1000; i++) {
            for (int j = 2; (j * i) <= 1000; j++) {
                prima[j * i] = false;
            }
        }

        int nTC = sc.nextInt();
        while (nTC-- > 0) {
            int N = sc.nextInt();

            int[] bilangan = new int[N];
            for (int i = 0; i < N; i++) {
                bilangan[i] = sc.nextInt();
            }

            int ke = 0;
            int jumlah = 0;
            for (int i = 0; i < N; i++) {
                if (prima[bilangan[i]]) {
                    jumlah += bilangan[i];
                    ke++;

                    if (jumlah > 100) {
                        break;
                    }
                }
            }

            System.out.println(ke);
        }
    }

}

Input dan output yang digunakan oleh juri dapat dilihat di sini.

  • Facebook
  • Twitter
  • Delicious
  • Digg
  • Google Buzz
  • StumbleUpon
  • Add to favorites
  • Email
  • RSS

Permanent link to this article: http://www.muhammadalvin.net/2011/11/artechno-festival-programming-competition-hitung-prima/

Older posts «