Anda di halaman 1dari 8

Pembahasan Soal bebek

Soal ini sepintas nampaknya rumit sekali tetapi dengan menganalisanya terlebih dahulu
maka anda akan menemukan soal yang jauh lebih sederhana.
Pertama kita bahas dahulu submasalah pengurutan bebek satu varietas, i.e."jika ada n
bilangan acak yang masing-masing unik, berapa banyak pemindahan minimum yang
perlu dilakukan untuk mengurutkannya".
Ide dari pemecahan masalah ini adalah: mencari berapa banyak di antara bilanganbilangan itu yang sudah dalam pengurutan. Ada sejumlah cara pengurutan, oleh pada
setiap bilangan kita hitung suatu indeks keterurutan (IK) yang didefinisikan sbb.
IK suatu bilangan adalah adalah jumlah bilangan disebelah kirinya yang lebih kecil
darinya namun berada dalam keterurutan termasuk bilangan itu sendiri.
Perhatikan bilangan-bilangan ini: 1, 3, 2, 7, 4, 6, 5
Indeks-indeks keterurutan diperoleh sbb (dituliskan di dalam tanda kurung),
1(1), 3(2), 2(2), 7(3), 4(3), 6(4), 5(4)
Berapa banyak bilangan yang tidak dalam keterurutan adalah banyaknya bilangan
dikurangi oleh IK maksimum. Untuk contoh tersebut maka IK maksimum adalah 4 dan
ada 7 bilangan sehingga jumlah pemindahan (yang dilakukan pada bilangan yang tidak
berada dalam urutan tersebut) adalah 7 -4 = 3.
Sekarang jika kita lakukan pada bilangan-bilangan ini: 1, 2, 3, 4, 5, 6, 7 Maka diperoleh
1(1), 2(2), 3(3), 4(4), 5(5), 6(6), 7(7) dan jumlah pemindahan adalah = 7 - 7 = 0.
Kita coba lagi pada bilangan-bilangan ini: 7, 6, 5, 4, 3, 2, 1 Maka diperoleh 7(1), 6(1),
5(1), 4(1), 3(1), 2(1), 1(1)
dan jumlah pemindahan adalah = 7 - 1 = 6.
Beruntunglah soal ini tidak meminta cara-cara pemindahannya karena untuk contoh di
atas akan terdapat banyak kemungkinan yang dapat dilakukan untuk 3 kali pemindahan
tesebut. Itu terlihat dari adanya indeks yang sama seperti bilangan 3 dan 2, bisa 2 maupun
3 yang dipindahkan.
Ok, jadi bagaimana algoritmanya? Saat menghitung IK untuk X[j] kita cukupmenemukan
bilangan yang lebih kecil darinya dengan IK terbesar, misalnya X[k], dan menghitung
IK[j] := IK[k] + 1
for j := 1 to N do begin
IKtmp := 0;
for k := 1 to j-1 do
if (X[k] < X[j] and IK[k] > IKtmp) then

IKtmp := IK[k];
IK[j] = IKtmp + 1;
end;

Sekarang bagaimana dengan varietas lebih dari satu? Gampang, karena soal membatasi
jumlah varietas hanya 4 maka pertama kita permutasikan urutan varietas, lalu memberi
tambahan bobot sesuai dengan urutan varietasnya. Misalnya untuk urutan varietas v1, v2,
v3, v4 maka bobot setiap bebek dari v2 di tambah 100, dari v3 di tambah 200, di v4 di
tambah 300 (mengapa kelipatan 100? Karena bobot maksimum bebek 100!). Kemudian
untuk satu permutasi dilakukan penghitungan IK sepertinya hanya satu varietas saja.
Untuk jumlahvarietas = 4 maka terdapat 24 permutasi, berati pula ada 24 kali
penghitungan IK dan masing-masing diperoleh jumlah pemindahan yang perlu dilakukan.
Dari ke 24 jumlah pemindahan untuk masing-masing permutasi diambil jumlah yang
paling minimum.
Lalu, bagaimanakah melakukan permutasi? Silahkan membaca lagi bahan PJJ yang
lalu....

Pembahasan Soal Kartu


Soal ini dibuat bukan untuk level IOI karena batasan data masih memungkinkan cara-cara
konvensional tanpa perlu adanya trick-trick canggih. Singkatnya, solusinya dapat dibuat
secara naif dan sederhana sbb.
Pertama anda memerlukan suatu array untuk menyimpan urutan kartu-kartu tsb dan kita
sebut array X, yang berindeks 0, 1, 2, ..., N-1. Untuk memudahkan algoritma maka kita
nomori ulang setiap kartu dengan mengurangi 1 pada setiap angka. Jadi X[i] array mulamula berisi kartu i.
Jika jumlah baris adalah k dimana k=N/3, deal demi deal isi array akan mengalami
pemindahan isi sbb. Kartu yang ada di X[0] tetap pada x[0],
kartu di X[1] pindah ke X[k],
kartu di X[2] pindah ke X[2k],
kartu di X[3] pindah ke X[1],
kartu di X[4] pindah ke X[k+1],
kartu di X[5] pindah ke X[2k+1],
kartu di X[6] pindah ke X[2],
kartu di X[7] pindah ke X[k+2]
... dst
sehingga secara umum
kartu di X[j] akan pindah ke X[(j mod 3) * k + j div 3].
Dalam implementasinya tentu saja operasinya dilakukan pada array yang berbeda sbb.

for j := 0 to N-1 do
Y[(j mod 3) * k + j div 3] := X[j];
X := Y;

Pada setiap deal nomor kolom dimana kartu yang diambil tsb berada disebutkan, yaitu
kolom c, dan kartu-kartu pada kolom c tsb ditandai. Untuk penandaannya ada yang
menggunakan flag boolean, yaitu dengan menandai false kartu-kartu yang tidak berada di
kolom c (inisialisasi semua true). Kartu-kartu i dengan flag[i] =true semakin lama
semakin sedikit dan akhirnya tersisa kartu yang mungkin.
Cara tersebut memerlukan iterasi sebanyak jumlah kartu. Cara lain yang lebih efisien
adalah menggunakan counter. Sebelum deal-deal dilakukan, setiap count[j] diinisialisasi
0. Ketika masukan adalah kolom c (c =1, 2, atau 3) maka counter dari setiap kartu pada
kolom tsb bertambah 1. Dalam Pascal:
for i := 0 to k-1 do
inc(count[X[(c-1)+i*3]]);

yang hanya melakukan N/3 iterasi saja. Cara ini akan semakin lebih efisien jika dalam
soal jumlah kolom besar.
Untuk soal standart IOI, biasanya ukuran data di paskan ke ukuran maksimum memori
yang bisa digunakan sehingga cara-cara naif seperti ini masih perlu diefisienkan lagi.
Misalnya operasi deal kartu hanya dilakukan pada array X saja. Misalnya kita mulai dari
X[1] dipindahkan ke X[k], X[k] dipindahkan ke X[(k mod 3)*k + k div 3], dst.
Jika jumlah deal adalah ITER maka kartu-kartu yang mungkin adalah kartu-kartu j
dengan COUNT[j] = ITER.
first := true;
for j := 0 to N-1 do begin
if (COUNT[j] = ITER) begin
if not first then begin
write(' ');
first := false
end;
write(j+1) {penomoran kartu dikembalikan ke urutan dari 1,
2, }
end

end;

Pembahasan Soal Paste


Tanpa menganalisis soal ini secara hati-hati mungkin anda langsung berfikir perlunya
suatu struktur data untuk menyimpan array untuk mencatat posisi baris-baris selama

operasi-operasi itu dilakukan. Itu masih OK kalau N masih kecil. Kalau kebetulan dalam
testcase digunakan N = 100000 maka anda akan menghadapi masalah memory untuk
mengalokasi array sebesar itu.
Dengan membacanya dan menganalisisnya dengan lebih hati-hati maka anda akan
menemukan kesederhanaan masalah ini.
Pertama, operasi cut-and-paste itu bersifat reversible. Artinya, dari hasil suatu operasi kita
bisa cari asalnya sebelum operasi itu dilakukan. perhatikan contoh berikut ini (baris-baris
ditulis ke kanan dengan pemisah tanda koma).
Misalnya sebelum operasi baris-baris berisi:
a, b, c, d, e, f, g, h, i, j
setelah operasi cut(4, 8),
maka akan dihasilkan baris-baris
a, b, c, i, j
dengan (d, e, f, g, h) di dalam 'buffer'. Setelah paste(2) dihasilkan baris-baris
a, b, d, e, f, g, h, c, i, j
Sekarang kita balikan (reversi) operasinya.
Operasi paste dilakukan setelah posisi ke 2. Jadi posisi-posisi 1 - 2 (yaitu a, b) setelah dan
sebelum paste sama. Kemudian karena operasi cut dilakukan pada 5 baris maka sejak
posisi ke 3 - 7 (yaitu d, e, f, g, h) adalah berasal dari hasil paste isi buffer. Dan, posisi ke 8
- 10 (yaitu c, i, j) mengalami pergeseran sebanyak 5 posisi ke kiri; jadi sebelum paste ada
di posisi ke 3-5. Jadi sebelum paste adalah a, b, c, i, j. Sementara, d, e, f, g, ada di 'buffer'.
Operasi cut(4,8) tidak mempengaruhi posisi 1 - 3 karena dilakukan mulai baris ke 4.
Berarti terjadi pergeseran baris ke 4 - 5 (yaitu i, j) sebanyak 5 posisi ke kanan. Di tengah
dimasukan yang ada di buffer.
Secara umum jika ditanyakan berasal dari mana baris yang sekarang bernomor x sebelum
operasi cut-and-paste (M, A, S). Berikut ini kita formulasikan perncarian harga z yaitu
nomor baris dari baris x berasal. Maka, terdapat sejumlah kemungkinan kasus:
Reversi Paste mencari y dari x

jika x <= S maka sebelum paste tetap, yaitu y = x


jika x > (S+A-M+1) maka sebelum paste x mengalami pergeseran sebanyak (AM+1) baris, yaitu y = x+A-M+1
jika x > S and x <= (S+A-M+1) maka sebelum paste x ada di "buffer" pada posisi
y' = x-S.

Reversi Cut mencari z dari y atau y' (di buffer)

Jika ada di buffer (yaitu y') maka z = M + y'-1

jika tidak ada dibuffer (yaitu y), maka


o jika y < M maka sebelum cut tetap, yaitu z = y
o jika y >= M maka sebelum cut ada di sebelah kanannya, yaitu di z = y+AM+1

Jika dilakukan sejumlah operasi, maka untuk suatu harga x reversi operasi tsb dilakukan
dari yang terakhir hingga yang pertama. Harga z dari operasi ke p menjadi x dari operasi
ke p-1, secara berulang. Karena x hanya diminta untuk 10 baris pertama saja maka
algoritma ini anda hanya melakukan reversi sebanyak 10 x jumlah operasi.
Nah, anda sekarang hanya perlu suatu array (berukuran 1000 x 3 integer) untuk
menyimpan seluruh parameter operasi tsb dan sementara buffer' itu sebenarnya tidak ada!
(Lho koq bisa??)

LABIRIN
Harry Potter sedang terjebak dalam suatu labirin (labirynth) bawah tanah yang berisi bom
waktu. Dalam labirin terdapat sejumlah ruangan dengan koridor-koridor yang
menghubungkannya. Setiap koridor hanya menghubungkan tepat dua ruangan yang
berbeda dan setiap pasang ruangan oleh satu koridor atau tidak sama sekali. Ruang-ruang
itu bisa berada dalam salah satu dari dua status: terkunci atau tak terkunci. Seseorang
tidak bisa masuk ke dalam ruang yang tekunci, tapi ia bisa keluar dari ruangan yang
terkunci itu. Sementara seseorang bisa keluar masuk ruang tak terkunci.
Di beberapa ruang terdapat tombol yang apabila ditekan akan mengubah status sejumlah
ruang. Misalnya, ruang yang terkunci menjadi tidak terkunci dan sebaliknya ruang yang
tak terkunci menjadi terkunci. Tentu saja jika Harry Potter berada di dalam ruangan yang
memiliki tombol, ia tidak harus menekannya. Ia baru menekan manakala ia
memerlukannya.
Salah satu ruang terdapat tangga untuk naik ke atas. Tuliskan suatu program dengan nama
LABIRIN.PAS yang dapat membantu Harry Potter yang berada dalam salah satu ruang
menemukan ruang yang berisi tangga naik ke atas itu termasuk tombol-tombol mana
yang harus ditekan. Karena dikejar waktu program harus menemukan jumlah koridor
yang harus dilalui Harry Potter, yang mungkin disertai dengan menekan tombol-tombol
di ruangan tertentu ia sempat berada.
Masukan berisi deskripsi ruangan serta koridor-koridor dalam labirin tersebut, ruangan
saat awal Harry Potter berada, dan daftar sejumlah tombol serta masing-masing ruangan
yang statusnya berubah jika tombol tersebut ditekan.

Format Masukan

Masukan adalah file teks bernama LABIRIN.IN dengan format sebagai berikut. Baris
pertama dari file masukan berisi dua integer yaitu N, yang menyatakan jumlah total
kamar (1 N 100), dan S, yang menyatakan jumlah tombol (jumlah kamar yang
berisikan tombol) (1 S 8). Tombol-tombol terlekat pad kamar-kamar bernomor 1
sampai S.
N baris berikutnya berisi deskripsi setiap kamar. Nomor kamar i pada baris ke (i+1). Pada
setiap baris tersebut jika dimulai dengan 0 menandakan bahwa pada mulanya kamar tbs
tak terkunci atau jika dimulai dengan 1 menandakan pada mulanya kamar ybs terkunci.
Setelah spasi terdapat bilangan integer K, yang menyatakan jumlah kamar yang
berhubungan dengan kamar ybs melalui koridor-koridor. Masih dalam baris yang sama,
setelah satu spasi setelah terdapat K bilangan yang menyatakan nomor-nomor kamar tsb
dengan penulisan yang dipisahkan spasi.
Dalam S baris berikutnya terdapat tombol-tombol, dari kamar pertama hingga kamar ke
S.
Setiap dari baris-baris tsb dimulai dengan bilangan integer L, yang menyatakan jumlah
kamar yang akan berubah jika tombol ditekan. Setelah spasi, berikutnya adalah L integer
yang masing-masing menyatakan nomor-nomor kamar ybs yang masng-masing
terpisahkan satu spasi.
Baris terakhir berisi dua bilangan A dan B; A adalah nomor kamar Harry Potter saat ini
berada dan B nomor kamar yang berisi tangga naik ke atas.

Format Keluaran

Keluaran adalah file LABIRIN.OUT yang hanya berisi satu bilangan integer yang
menyatakan jumlah minimal koridor yang harus dilalui untuk mencapai ruangan
bertangga.
Note: Setiap data test dijamin selalu memiliki solusi, artinya dari ruang A selalu ada jalan
untuk mencapai ruang B.

Contoh

LABIRIN.IN
41
013
1234
0212
012
12
34

LABIRIN.OUT
4

LABIRIN.IN
52
0225
1213
0224
1235
0214
224
234
53

LABIRIN.OUT
3

LABIRIN.IN
62
0265
1246
014
13253
03146
03152
3253
14
63

LABIRIN.OUT
8