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’
. 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.
Komentar Terkini