Pembahasan Soal labirin

Ini memang soal yang paling sulit di antara semua soal yang diberikan. Namun, ternyata anda masih bisa memecahkannya jika bisa memahami penjelasan sbb ini.

Masalah ini termasuk masalah graph traversal dengan metoda breadth first search (BFS). Untuk memudahkan pemahaman anda, pertama kita membahas kasus tanpa adanya switch. Dengan tidak adanya variabel-variabel switch maka anda bisa mengimplementasikan BFS (hanya dengan sejumlah modifikasi kecil) pada graph dengan verteks-verteks graph adalah ruang-ruang dan lorong-lorong penghubung adalah edge-edge graph.

Untuk submasalah ini BFS memerlukan suatu queue untuk menyimpan verteks-verteks pada breadth yang akan ditraverse berikutnya. Algoritma BFS untuk masalah ini tanpa switch adalah sbb. (Warning: algoritma ini adalah pascal-like pseudocode, bukan Pascal code, jadi harap anda memaklumi kalau ada syntax error!).

function labirin(Start: vertex, Target: vertex): integer;
var 
    Q: queue;
    qe,qe2: queueElement;
    i,adjlen: integer;
begin
    initQueue(Q); {mengosongkan queue}
    qe.room := Start;
    qe.pathlen := 0;
    putInQueue(Q, qe);

    while (notEmpty(Q)) begin
        qe := getQueue(Q);
        if (qe.room = Target) begin
             labirin := qe.pathlen;
             exit;
        end;
	p = getUnvisitedUnlockedAdjacentRoom(qe, S adjlen);
        for i := 1 to adjlen do begin
            qe2.room := p[i];
            qe2.pathlen := qe.pathlen + 1;
            putInQueue(Q,qe2);
        end;
    end;
    
end;
Function getUnvisitedUnlockedAdjacentRoom(qe, S,adjlen) adalah untuk mendapatkan verteks berikutnya yang berhubungan langsung dengan verteks qe dan belum pernah dimasukan dalam queue. Agar bisa mengetahui apakah verteks pernah masuk ke dalam queue atau tidak maka setiap verteks terdapat variabel boolean visited yang diinisialisasi false dan di dalam getUnvisitedUnlockedAdjacentRoom(qe, S, adjlen) akan di-true-kan. Algoritma akan bekerja hingga qe adalah verteks target yang sedang dicari. Jumlah koridor dinyatakan dengan pathlen yang dicatat pada verteks tersebut.

Nah sekarang, untuk kasus dengan adanya switch maka kerumitannya meningkat sbb. Setiap ruang memiliki status locked atau unlocked yang dapat secara dinamis berubah-ubah sesuai dengan penekanan tombol yang mempengaruhinya. Kita coba melihat masalah sbb. Satu verteks bukan lagi satu ruang, tetapi suatu ruang dengan status S switch yang berbeda sebagai suatu vektor (noruang, s1s2...sS). Setiap switch memiliki harga biner 0 dan 1. Harga switch = 0 jika penekanan switch dilakukan dalam jumlah yang genap, dan = 1 jika ganjil. Deratan harga switch s1s2..sS ini membentuk suatu bilangan yang kita sebut X. karena soal membatasi S <= 8, maka 0 ≤ X < 256.

Jadi, untuk N ruang dan S switch akan ada Nx2S verteks yang berbeda. Sementara untuk graph tanpa adanya switch hanya berisi N verteks. Untuk memudahkan pembahasan kita selanjutnya menyebut graph tanpa switch tsb sebagai plain graph.

Untuk masalah dengan switch ini graph berbentuk multilayer graph sbb. Jika jumlah switch adalah S maka jumlah layer adalah 2S. Layer pertama adalah plain graph dengan adanya X=0. Setiap layer berikutnya adalah juga plain graph dengan harga X yang berbeda (tapi sama pada layer yang sama!). Jika dalam plain graph terdapat edge antara vi dan vj maka juga ada dalam (vi,X) dengan (vj,X). Sementara keterhubungan antara layer: jika pada Vi tdp switch (dalam soal dibatasi i <= S), maka terdapat edge antara (vi,X1) dan (Vi, X2) dengan X1 dan X2 hanya berbeda tepat di bit ke-i. Karena edge antara layer ini masih di ruangan yang sama maka dalam penghitungan jumlah lorong yang dilalui, edge ini tidak termasuk yang dihitung.

Dalam implementasinya multilayer graph ini cukup diwakili oleh satu plain graph (untuk memeriksa keterhubungan antar ruangan) dengan harga-harga (Vi,X) disimpan dalam tabel. Karena jumlah verteks plain graph maksimum 100 dan S paling banyak 8 maka untuk menghemat memory (Vi,X) bisa direpresentasikan sebagai index dari array status dengan panjang maxsimum 25600. Untuk mendapatkan harga komponennya maka dari harga indeks tsb anda dapat gunakan operasi-operasi and/or/xor/mod/div. Array status tsb bisa digunakan untuk mencatat pathlen dan status visited.

Apalagi ya?? Hmm. bagaimana perubahan lock-unlock suatu ruangan dapat diikuti? Misalkan ruangan J. Jika berada pada harga switch X= s1, s2, ..., sS maka untuk setiap bit si = 1 dari X dan switch di ruang-i mempengaruhi ruang J tsb maka status lock dari ruangan tsb (variabel lockstate) ditoggle:
lockstate := not lockstate. Misalnya s1, s4 dan s8 yang berharga 1. Kita periksa apakah switch di ruang 1, 4 dan 8 mempengaruhi J? Jika hanya 1 dan 4 yang mempengaruhi J berarti ruang J di toggle dua kali alias kembali seperti semula. Jika ketiganya mempengaruhi J maka status ruang J kebalikan dari semula. Pemeriksaan tersebut saat menjalankan getUnvisitedAdjacentRoom dilakukan. Jika verteks berikutnya dalam status locked maka tentu tidak dapat dimasukan ke dalam queue.

Ok, sekarang kita lihat contoh masukan pertama dari soal.

4 1
0 1 3
1 2 3 4
0 2 1 2
0 1 2
1 2
3 4
Soal ini digambarkan secara plain graph pada gambar berikut ini. Kamar no 2 locked, dan kamar lainnya unlocked. Harry Potter akan mencari jalan dari ruang 3 ke ruang 4.

 

 

 

 

 

 

 

 

Dalam representasi multilayer graph terdiri dari dua layer karena jumlah switch hanya satu yaitu di kamar 1. Node-node di layer pertama adalah untuk harga switch X=0 dan di layer kedua untuk harga switch=1. Antara kedua layer terhubungkan link antara (1, 0) dengan (1, 1) yang menyatakan jika di sedang berada di (1,0) dan menekan switch maka akan berpindah ke (1,1) dan juga sebaliknya jika menekan switch kembali.

 









 

 

 

 

 

 

 

Dari (3,0) maka penelusuran akan membawa ke (1,0), terus ke (1,1) dan (3,1). Dari situ dapat masuk (2,1) karena sudah unlock, kemudian sampailah di (4,1). Jumlah path yang dilakui adalah 4 karena antara (1,0) ke (1,1) tidak dihitung.