Anda di halaman 1dari 25

LAPORAN TUGAS KELOMPOK PAAL A

Oleh: Aldy Ahsandin Mohammad Farid Naufal Ahmad Sodik 5109100704 5110100094 5110100125

JURUSAN TEKNIK INFORMATIKA FAKULTAS TEKNOLOGI INFORMASI INSTITUT TEKNOLOGI SEPULUH NOPEMBER 2012

Pembagian Pekerjaan
Aldy Ahsandin (5109100704) 1. Basic Routines 2. Buzz Trouble Mohammad Farid Naufal (5110100094) 1. Collision Issue (CDC12_C) 2. Drastic Race (CDC12_D) 3. Halt the War (CDC12_H) Ahmad Sodik 1. Innovative Combination (CDC12_1) 2. Forbidden Machine (CDC12_F)

SPOJ PROBLEM Basic Routines Problem code: CDC12_C

Analisis Testcase (simbol T) Jumlah kegiatan ( simbol N) Energi yang dimiliki Ronny (simbol E) Aktivitas beserta energi yang dibutuhkan ( simbol A dan V)

Ketika akan mengerjakan problem ini, pemecahan yang terbayang adalah dengan menggunakan Knapsack. Bayangan itu beralasan karena problem ini memiliki beberapa variabel yang memiliki kesamaan dengan Knapsack problem. Kesamaan itu antara lain energi yang terbatas, adanya masing-masing aktivitas yang memiliki nilai energi, dan pencarian jumlah maksimum/minimum aktivitas. Secara umum pemecahan problem Knapsack memanfaatkan array dua dimensi. Seperti problem Knapsack di bawah ini beserta solusinya.

Tabel Soal Knapsack

Tabel Solusi Knapsack

Jika memperhatikan solusi Knapsack di gambar, solusi tersebut memanfaatkan array dua dimensi dimana baris dan kolom merepresentasikan W=berat dan i=benda. Hasil maksimumnya adalah value 13. Agar mencapai nilai maksimum 13 yang ada di pojok kanan bawah harus melakukan pengisian sebanyak i*w. Pemecahan menggunakan solusi Knapsack mulai dipertanyakan karena kami bingung memodifikasi array tanpa harus melakukan scanning sebanyak i*w sementara di problem Basic Routines jumlah aktivitas maksimum dan energi maksimum adalah 1 N 100,000 dan 1 E 1,000,000. Berarti jika dibuat array dua dimensi NxE, program harus menscanning data sebanyak 105 x106 . Apabila itu dilakukan ada kemungkinan akan Time Limit Excedeed atau TLE. Selain itu di dalam problem Basic Routine juga mempertimbangkan prioritas lexicographical apabila aktivitas memiliki energi yang sama. Maka kami beralih untuk mencari algoritma lain. Algoritma yang kami gunakan adalah melakukan sorting berdasarkan prioritas. Maksudnya, untuk mengambil aktifitas mana saja yang dapat dilakukan Ronny, diurutkan berdasar prioritas value dan lexicographical aktifitas. Sehingga setelah terurut, Ronny dapat mengambil aktifitas dengan value energi terkecil hingga mencapai energi maksimum yang dimiliki Ronny.

Algoritma Untuk menyimpan data dua tipe data aktivitas(string) dan value(int) yang berbeda kami memerlukan STL Pair. String Aktifitas Int Value

Lalu setiap Pair itu dikumpulkan dalam vector bernama data. 0 aktifitas value 1 aktifitas value 2 aktifitas value ... aktifitas value N-1 aktifitas value

Hasil aktivitas yang dikerjakan Ronny akan disimpan dalam vector _hasilKegiatan.

Setelah beberapa kali coretan, kami akhirnya membuat Algoritma dari pemecahan problem Basic Routines seperti berikut. 1. Masukkan data aktivitas dan value(energi)nya ke dalam Pair

2. Masukan Pair tersebut ke dalam Vector<Pair> data 3. Lakukan sort berdasarkan a. Value dari aktivitas. Mulai dari value terkecil hingga terbesar. b. Apabila value sama maka sort berdasar lexicographicalnya 4. Mulai dari i=0 hingga E energi. a. Jika (Energi-data[i].second>=0) i. Masukkan data[i].first ke _hasilKegiatan ii. Energi=Energi-data[i].second+(Kegiatan ke i+1); 5. Cetak _hasilKegiatan

PseudoCode 1. Masukkan data aktivitas dan value energinya ke dalam Pair


... //input For i=0; i<N; i++ Input _namaKegiatan Input _energi _pasangan=make_pair(_namaKegiatan, _energi); ...

2. Masukkan Pair tersebut ke dalam Vector<Pair> data


data.push_back(_pasangan);

3. Sort

sort( data.begin, data.end, less_than_second);

/* Fungsi Sort */ less_than_second( pair b1, pair b2 ){ if(b1.second < b2.second)return true; /*Jika energi aktivtias berbeda */ else if(b1.second==b2.second){ //Jika energi aktivitas sama if(b1.first<b2.first) return true; else return false; } else return false; }

Lakukan sort berdasarkan a. Value dari aktivitas. Mulai dari value terkecil hingga terbesar. b. Apabila value sama maka sort berdasar lexicographicalnya

4. Mengambil energi
... For i=0; i<N; i++ if(Energi-data[i].second>=0){ hasilKegiatan.push_back(data[i].first); //Simpan ke _hasilKegiatan jumlahKegiatan++; Energi=Energi-data[i].second+jumlahKegiatan; //Kurangkan energinya } else { i=N; } ...

Mulai dari i=0 hingga E energi. Jika (Energi-data[i].second>=0) atau masih memiliki energi i. Masukkan data[i].first ke _hasilKegiatan ii. Energi=Energi-data[i].second+(Kegiatan ke i+1);

5. Cetak _hasilKegiatan
cetak(){ for i=0; i<jumlah; i++ cetak hasilKegiatan[i] }

Kompleksitas dari algoritma ini adalah O(E) yaitu sebanyak energi yang dimiliki oleh Ronny.

Buzz Trouble Problem code: BUZZOFF


Analisis Berdasarkan informasi dari rekan kami Ahmad Sodik, problem ini memperlihatkan pola penjumlahan bilangan Fibonacci. Jadi hasil dari input problem ini akan menghasilkan output seperti berikut
Input Fibonacci Output

0 1 2 3 4 5 6

1 1 2 3 5 8 13

1 1+ 2 = 3 1+2+3 = 6 1+2+3+5=11 1+2+3+5+8=19 1+2+3+5+8+13=32

Melihat output yang ditampilkan, sebenarnya kita bisa menggunakan dynamic problem. Karena input ke n menghasilkan n ditambah akumulai n-1. Tapi kemungkinan akan Time Limit Excedeed apabila data inputannya mencapai 1018. Kita dapat mencari bilangan Fibonacci ke-n dengan menggunakan formula Binet:

Untuk menjumlahkan bilangan Fibonacci hingga ke n

= fibonacci1+ fibonacci2+ fibonacci3 fibonacci4+ .... fibonaccin

=Fibonaccin+3 2
Jika dibuat implementasi dalam C++ kami membuat seperti berikut.
hasil=((pow(((1+sqrt(5))/2),N+3)-pow(((1-sqrt(5))/2),N+3))/sqrt(5))-2;

Setelah dicoba berkali-kali ternyata nilai pow akan menghasllkan bilangan desimal 0,00... yang dapat menyebabkan hasil akhir tidak akurat. Oleh karena itu kita membuat satu fungsi pangkat baru dengan pseudocode seperti di bawah ini.

double pows(a, b){ if(b == 0) return 1LL; buff=pows(a,b/2); buff *=buff; buff=fmod(buff,MOD); if((b%2)==1){ buff *=a; } buff=fmod(buff,MOD); return buff; }

Pows ini akan bekerja dengan cara memecahnya menjadi dua bagian dan akan melakukan rekursi pecah dua bagian lagi hingga pangkat terkecil. Contohnya, jika ada 1012, fungsi ini akan memecah menjadi 106 dan 106. 106 itu akan dipecah juga lagi menjadi 103 dan 103. Begitu seterusnya. Setiap kali dipecah akan dikalikan nilainya. Sehingga akan diketahui berapa nilai pangkatnya. Sayangnya nilai pows kami juga tetap menghasilkan bilangan desimal. Kami memahami problemnya bukan terletak pada pows tapi pada formula implementasi yang kami buat itu sendiri. Akhirnya kami beralih untuk mencari formula cepat mencari bilangan fibonacci ke n lain selain menggunakan Binet. Setelah melakukan pencarian akhirnya menemukan pemecahan fast fibonacci menggunakan Matrix Exponentiation. Fibonacci sendiri memiliki matrix identitas seperti di bawah ini.

Sekarang jika diletakkan angka fibonacci yang pertama ke matriks sebalah kanan dan akan dikali hasilnya

Atau sama dengan juga

Cara cepat untuk melakukan perpangkatan adalah dengan algoritma di bawah ini

Array fib di bawah mewakili bilangan matriks fibonacci.


fib[2][2]= {{1,1},{1,0}}, ret[2][2]= {{1,0},{0,1}}, tmp[2][2]= {{0,0},{0,0}};

Kemudian dibuat fungsi Fibonacci dengan input n. Selanjutnya dilakukan pengecekan apakah nilai n bilangan genap atau ganjil Jika ia ganjil Lakukan dua kali pengisian matriks tmp seperti di bawah ini. Jika genap cukup satu kali. Cara di bawah adalah mengalikan matriks ret dan fib. Hasil matriks tmp dimodulos 10000000007
for(i=0; i<2; i++) for(j=0; j<2; j++) for(k=0; k<2; k++){ tmp[i][j]=(tmp[i][j]+ret[i][k]*fib[k][j]); tmp[i][j]%=MOD; } for(i=0; i<2; i++) for(j=0; j<2; j++) ret[i][j]=tmp[i][j];

Nilai tmp akan menjadi nilai fibonacci, setelah itu n/2 artinya dikecilkan pangkatnya
for(i=0; i<2; i++) for(j=0; j<2; j++) fib[i][j]=tmp[i][j]; n/=2;

Setelah menggunakan fast fibonacci itu kita mengetahui bahwa kita tidak memerlukan lagi fungsi pows yang telah dibuat dan rumus pencarian jumlah fibonacci cukup seperti Fibonaccin+3 2. Kompleksitas dari fast fibonacci adalah O(log n).

SPOJ Problem Set (classical) 12558. Collision Issue Problem code: CDC12_C
Solusi Untuk mengetahui panjang sisi dari segitiga ABC kita dapat menghitungnya dengan rumus Pythagoras. Misal untuk Test Case pertama (untuk input titik poin yang decimal harus dibulatkan 2 angka di belakang koma): a (Xa, Ya) = (0, 0) b (Xb, Yb) = (0, 3) c (Xc, Yc) = (3, 0) Kita umpamakan segitiga yang belum kita ketahui bentuknya seperti gambar di bawah :

Untuk mencari panjang titik a ke b adalah C= = =3

Untuk mencari panjang titik b ke c adalah A= = =

Untuk mencari panjang titik a ke b adalah

B=

=3

Dari rumus untuk mencari sudut yang terdapat di soal untuk mecari sudut C: =C

= C2

= A2 + B2 C2
= (A2 + B2 C2 ) / = (A2 + B2 C2 ) /

sehingga : cos() = (A2 + B2 C2 ) / = (18 + 9 9 ) / cos() = (A2 + C2 B2 ) / = (18 + 9 9 ) / cos() = (B2 + C2 A2 ) / = (9 + 9 18 ) /

(untuk c) (untuk b) (untuk a)

Karena kita ingin mencari sudutnya maka kita gunakan aturan arc cos. Untuk rumus di atas adalah untuk mencari sudut c. Kita juga perlu membulatkan setiap sudut 2 angka di belakang koma. c = acos ( cos() ) = 45 b = acos ( cos() ) = 45 a = acos ( cos() ) = 90 Sekarang kita sudah mengetahui besar sudut dan besar panjang dari segitiga di atas. Oleh karena itu kita sudah dapat menentukan nama segitiga yang kita cari. Dikarenakan terdapat sisi yang sama dan adanya sudut yang besarnya 90 maka nama segitiga adalah Isosceles Right Triangle Pseudocode
A = sqrt( abs(x3-x2) * abs(x3-x2) + abs(y3-y2) * abs(y3-y2) );

B = sqrt( abs(x3-x1) * abs(x3-x1) + abs(y3-y1) * abs(y3-y1) ); C = sqrt( abs(x2-x1) * abs(x2-x1) + abs(y2-y1) * abs(y2-y1) ); /*Mencari cosinus cosA = (B*B + C*C cosB = (A*A + C*C cosC = (A*A + B*B dari setiap sudut berdasarkan - A*A) / ( pow(8*B*B*B*C*C*C, - B*B) / ( pow(8*A*A*A*C*C*C, - C*C) / ( pow(8*A*A*A*B*B*B, rumus di 1.0/3.0) 1.0/3.0) 1.0/3.0) atas*/ )); )); ));

/*Sudut dibulatkan dua angka angleA = floor( (acos (cosA) angleB = floor( (acos (cosB) angleC = floor( (acos (cosC)

di belakang koma*/ * 180.0 / PI )*100 + 0.5)/100; * 180.0 / PI )*100 + 0.5)/100); * 180.0 / PI )*100 + 0.5)/100);

/*panjang sisi dibulatkan dua angka di belakang koma*/ A = floor(A*100 + 0.5) / 100; B = floor(B*100 + 0.5) / 100; C = floor(C*100 + 0.5) / 100; if(A == B && A == C && B == C) print "Scenario #%d: Equilateral Equiangular\n" else if(A == B || A == C || B == C) if(angleA == 90.00 || angleB == 90.00 || angleC == 90.00) print "Scenario #%d: Isosceles Right Triangle\n" else if(angleA > 90.00 || angleB > 90.00 || angleC > 90.00) printf("Scenario #%d: Isosceles Obtuse\n", i); else print "Scenario #%d: Isosceles Acute\n" else if(angleA == 90.00 || angleB == 90.00 || angleC == 90.00) { print "Scenario #%d: Scalene Right Triangle\n" else if(angleA > 90.00 || angleB > 90.00 || angleC > 90.00) { print "Scenario #%d: Scalene Obtuse\n" else print "Scenario #%d: Scalene Acute\n"

Karena dalam problem ini tidak menggunakan perulangan dalam solusinya maka kompleksitasnya O(1)

SPOJ Problem Set (classical) 12559. Drastic Race Problem code: CDC12_D
Solusi Contoh untuk Test Case yang pertama

t = Waktu K = Banyak kesempatan untuk menggunakan kecepatan boostnya s = Jarak yang ditempuh saat waktu t Ronny akan selalu menggunakan kemampuan Boostnya di saat dia masih memilikinya namun di saat kemampuannya tersebut habis dia berada di dalam suatu kondisi untuk memilih apakah harus berhenti terlebih dahulu untuk merecover kemampuan boostnya atau melanjutkan perjalanannya dengan kecepatan normalnya. Kondisi tersebut dapat diselesaikan seperti berikut : 1. Ronny tidak akan melakukan recover apabila dengan kecepatan normalnya di detik berikutnya ternyata dia telah sampai di finish. 2. Ronny tidak akan melakukan recover apabila kecepatan normalnya lebih dari kecepatan boostnya. Sehingga lebih baik dia terus menggunakan kecepatan normalnya hingga garis finish. 3. Ronny akan melakukan recover apabila dengan kecepatan normalnya di detik berikutnya dia belum sampai di finish dan kecepatan normalnya kurang dari kecepatan Boostnya.. Pseudocode
Drasticrace(tRainbow, distance, vRonny, boost, chance, recover) while(temp < distance) { if(chance > 0) distanceNow += vRonny + boost ans = ans + 1 chance = chance - 1 else if(vRonny > boost) distanceNow += vRonny;

ans = ans + 1 else if(temp + vRonny >= m) distanceNow += vRonny; ans = ans + 1 else chance = chance + recover ans = ans + 1 if(ans < tRainbow) print "Scenario #%d: Ronny wins in time %d\n" else print "Scenario #%d: Ronny will be annihilated\n"

Kompleksitas algoritma penyelesaian problem ini adalah O(D / V) Keterangan : D = Jarak menuju Finish V = Kecepatan regular Ronny

SPOJ Problem Set (classical) 12563. Halt The War Problem code: CDC12_H
Solusi Problem ini dapat diselesaikan dengan Segment Tree Range Sum. Dimana kita harus membentuk sebuah Tree untuk menyimpan jumlah letter yang di bawa oleh Rainbowlandian. Terdapat dua operasi fungsi pada tree yaitu untuk Update dan Query. Pseudocode (Update dan Propagate)
propagate(node, L, R, x) st[node] += (R-L+1)*x prop[node] += x return update(node, L, R, i, j) if (i<=L && R<=j){ propagate(node, L, R, 1) return mid = (L+R)>>1; if (prop[node] > 0) propagate(2*node, L, mid, prop[node]) propagate((2*node+1, mid+1, R, prop[node]) prop[node] = 0 if (mid>=i) update(2*node, L, mid, i, j) if (mid+1<=j) update(2*node+1, mid+1, R, i, j) st[node] = st[2*node] + st[2*node+1] return

Keterangan node L R I J St[] Prop[] = index array node = batas bawah = batas atas = Operasi update dimulai i = Operasi update sampai j = node tree untuk menyimpan value (dijelaskan di bawah) = node tree untuk penanda dan update (dijelaskan di bawah)

Untuk contoh kasus yang pertama kita dapat menggambarkan proses rekursinya sebagai berikut. Modification 1 2. Karena index kita mulai dari 0 maka kita kurang i dan j dengan 1.

Rumus utama dari tree ini adalah induk dari setiap node st[] merupakan jumlah array st[] dari anak anaknya.
st[node] = st[2*node] + st[2*node+1]

Fungsi Propagate merupakan fungsi penanda bahwa induk dari node telah dilakukan update dan juga untuk mengisi nilai dari array st[node] dengan nilai interval L sampai R. Misal kita akan melakukan update dari interval 1 sampai dengan 4 kita tidak perlu langsung melakukan operasi update sampai terhadap node anak anaknya. Namun apabila operasi membutuhkan update sampai anak anaknya baru kita lakukan operasi update. Untuk lebih jelasnya kita coba Query Modification 2 3.

Dari contoh di atas untuk operasi update(2, 0, 1, 1, 2) dikarenakan array prop[2] bernilai lebih dari nol maka kita juga harus lakukan proses update untuk node anak dari array index 2 yaitu array untuk index 4 dan 5.

Pseudocode (Query)
query(node, L, R, i, j) if (I <= L && R <= j) return st[node]; mid = (L+R) / 2; if (prop[node] > 0) propagate(2*node, L, mid, prop[node]) propagate(2*node+1, mid+1, R, prop[node]) prop[node] = 0 if (mid>=i) ret += query(2*node, L, mid, i, j); if (mid+1<=j) ret += query(2*node+1, mid+1, R, i, j); return ret

Untuk fungsi Query kita contohkan test case yang pertama. Answer 2, 2

Di dalam fungsi query juga terdapat fungsi propagate dikarenakan mungkin fungsi query akan menampilkan jumlah interval hingga node tertentu yang belum terupdate oleh node induknya atau nilai prop[node] induknya masih bernilai lebih dari 0. Dikarenakan solusi dari problem ini menggunakan konsep tree maka kompleksitasnya O(N log N)

SPOJ Problem Set (tutorial) 12561. Forbidden Machine Problem code: CDC12_F
Dalam problem ini programmer membuat sebuah program untuk dimasukkan dalam sebuah mesin, agar mesin dapat menunemukan jawaban yang sesesuai untuk guard. Penjelasan: N adalah no state dari machine. M adalah no transisi (perpindahan) mesin. I , J, C adalah perpindahan state dari i ke j yang berisi huruf C. F adalah akhir state. E adalah no yang menunjukkan final(akhir) state, Q adalah awal state. S adalah jumlah proses(test) yang dilakukan. Input :

N, M, F, Q 4810 0 01a 10a 12b 21b 03b 30b 32a 23a 3 ababbaa abababab aaaabbbb Output:
Scenario #1: ababbaa Rejected abababab Accepted aaaabbbb Accepted

I, J, C

Q S

Penyelesaian(penjelasan algorithma) dengan input: State(langkah) pada input dapat digambarkan sebagai berikut:

a 0 a 1

a 3 a 2

E adalah final state, maka akhir dari input char karakter S harus pada E. E = 0, maka akhir harus pada state 0. Q adalah awal state, maka awal langtkah dari input char harus pada state Q. Q = 0, maka awal state harus pada state 0.

ababbaa
langkah : 1. 2. 3. 4. 5. 6. 7. 0 1 2 3 0 3 2 1 = a (benar, ada arah dari 0 ke 1). 2 = b (benar, ada arah dari 1 ke 2). 3 = a (benar, ada arah dari 2 ke 3). 0 = b (benar, ada arah dari 3 ke 4). 3 = b (benar, ada arah dari 0 ke 3). 2 = a (benar, ada arah dari 3 ke 2). 3 = a (benar, ada arah dari 2 ke 3).

Dari uji diatas akhir state tidak pada state ke-0, maka kasus tersebut tidak di terima oleh mesin( output : Rejected ).

abababab
langkah : 1. 2. 3. 4. 5. 6. 7. 8. 0 1 = a (benar, ada arah dari 0 ke 1). 1 0 = a (benar, ada arah dari 1 ke 0). 0 1 = a (benar, ada arah dari 0 ke 1). 1 0 = a (benar, ada arah dari 1 ke 0). 0 3 = b (benar, ada arah dari 0 ke 3). 3 0 = b (benar, ada arah dari 3 ke 0). 0 3 = b (benar, ada arah dari 0 ke 3). 3 0 = b (benar, ada arah dari 3 ke 0).

Dari uji diatas akhir state pada state ke-0, maka kasus tersebut di terima oleh mesin( Output : Accepted ).

aaaabbbb
langkah : 1. 2. 3. 4. 5. 6. 7. 8. 0 1 = a (benar, ada arah dari 0 ke 1). 1 2 = b (benar, ada arah dari 1 ke 2). 2 3 = a (benar, ada arah dari 2 ke 3). 3 0 = b (benar, ada arah dari 3 ke 4). 0 1 = a (benar, ada arah dari 0 ke 1). 1 2 = b (benar, ada arah dari 1 ke 2). 2 3 = a (benar, ada arah dari 2 ke 3). 3 0 = b (benar, ada arah dari 3 ke 4).

Dari uji diatas akhir state pada state ke-0, maka kasus tersebut di terima oleh mesin( Output : Accepted ).
Pseudo code: time = 0
for(k=0...<=jmlState) { if(DP[time][k]) for(l=0....<=jmlState) if(array[k][l][charUji-'a']) { DP[time+1][l] = true } } time++; input char(charUji) }

Kompleksitas : Perulangan 1 l dari 0 sampai jmlSatate Perulangan 2 k dari 0 sampai jmlSatate l=k Kompleksitas = O( l*l) = O(2^l)

SPOJ Problem Set (tutorial) 12564. Innovative Combination Problem code: CDC12_I
Dalam problem ini, programmer membuat sebuah program untuk memecahkan sebuah code pasword yang lupa kombinasinya. Penjelasan: T adalah banyak uji coba. N adalah jumlah bilangan dalam sequence. M adalah jumlah bilangan special. Squence M adala rangkaian bilangan yang di masukkan. Squence N dalah rangkaian bilangan special.
Input:

3 52 33544 54 74 4855548 4485 10 6 3376557666 576635

Output:

Scenario #1: 12 Scenario #2: 2223 Scenario #3: 224422

Penyelesaian(penjelasan algorithma) dengan input: Permasalahan special number dapat digambarkan dengan berapa sering bilangan special number keluar dalam suatu rangkaian bilangan.

3 3 5 4 4
5 4 sehingga didapat , 5 ada 1 dan 4 ada 2, sehingga output 12

4 8 5 5 5 4 8

4485

Sehingga di dapat, 4 ada 2, 4 ada 2, 8 ada 2 dan 5 ada 3, sehingga output 2223

3 3 7 6 5 5 7 6 6 6

5 7 6 6 3 5

Sehingga di dapat: 5 ada 2, 7 ada 2, 6 ada 4, 6 ada 4, 3 ada 2 dan 5 ada 2, sehingga ouput 224422

Sedangkan untuk menghitung banyak bilangan yang muncul adalah for(i=1...<=N) B[num]=+1 Keterangan: Num = bilangan special B[num] = list bilangan index spesial Pseudocode
Innovative(Num, SN, N, M) for i to N b[Num] += 1 for i to M print b[SN]

Keterangan: Num = Special Number dalam sequence SN = Special Number N = panjang sequence M = panjang Special Number

Komplesitas: Perulangan 1 sampai N, sehingga kompleksitas O(n)

Anda mungkin juga menyukai