Tugas Ke-2
Disusun untuk memenuhi tugas Desain dan Analisis Algoritma
Disusun Oleh:
Kelompok 5 K5_L_T2
1. Ibrahim Kusuma 115090600111012
2. M Choirul Rahmadan 115090600111026
3. Abu Bakar 115090601111016
4. Wisnu Wijaya 115090607111018
5. Hammurabi Wisadono 115090607111030
6. Yusuf Aji Wibowo 115090613111004
Program Studi Informatika / Ilmu Komputer Program Teknologi Informasi dan Ilmu Komputer
Universitas Brawijaya
2013
A. Algoritma Knapsack Problem a. Definisi Algoritma Knapsack
Knapsack artinya karung/kantung. Karung mempunyai kapasitas muat terbatas. Barang-
barang dimasukkan ke dalam karung hanya sampai batas kapasitas maksimum karung saja.
Knapsack adalah salah satu masalah yang sering muncul dalam kasus optimasi dan kombinatorial yang banyak ditemukan pada literatur-literatur lama dan hingga kini
permasalahan ini masih banyak ditemukan dalam kehidupan sehari-hari. Dalam dunia nyata permasalahan Knapsack ini sering sekali digunakan terutama pada bidang (jasa)
pengangkutan barang (seperti pengangkutan peti kemas dalam sebuah kapal). Dalam usaha tersebut, diinginkan suatu keuntungan yang maksimal untuk mengangkut barang yang ada dengan tidak melebihi batas kapasitas yang ada. Berdasarkan persoalan tersebut, diharapkan ada suatu solusi yang secara otomatis dalam mengatasi persoalan itu.
Problem Knapsack adalah permasalahan optimasi kombinatorial, dimana kita harus mencari solusi terbaik dari banyak kemungkinan yang dihasilkan.
Knapsack Problem:
Diberikan bobot knapsack adalah M. Diketahui n buah objek yang masing-masing bobotnya adalah w1, w2, …, wn.
Tentukan nilai bi sedemikian sehingga M = b1w1 + b2w2 + … + bnwn
yang dalam hal ini, bi bernilai 0 atau 1. Jika bi = 1, berarti objek i dimasukkan ke dalam knapsack, sebaliknya jika bi = 0, objek i tidak dimasukkan.
b. Contoh Program
import java.util.Scanner;
/**
* ***********************************************************************
* Compilation: javac Knapsack.java Execution: java Knapsack N W
*
* Generates an instance of the 0/1 knapsack problem with N items and maximum
* weight W and solves it in time and space proportional to N * W using dynamic
* programming.
*
* For testing, the inputs are generated at random with weights between 0 and W,
* and profits between 0 and 1000.
*
* % java Knapsack 6 2000 item profit weight take 1 874 580 true 2 620 1616
* false 3 345 1906 false 4 369 1942 false 5 360 50 true 6 470 294 true
*
************************************************************************
*/
public class Knapsack {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// int N = Integer.parseInt(args[0]); // number of items
// int W = Integer.parseInt(args[1]); // maximum weight of knapsack
System.out.println("Algoritma Knapsack Problem");
System.out.print("Masukan jumlah item : ");
int N = scanner.nextInt();
System.out.print("Masukkan berat maksimum : ");
int W = scanner.nextInt();
int[] profit = new int[N + 1];
int[] weight = new int[N + 1];
// generate random instance, items 1..N
for (int n = 1; n <= N; n++) {
profit[n] = (int) (Math.random() * 100);
weight[n] = (int) (Math.random() * W);
}
// opt[n][w] = max profit of packing items 1..n with weight limit w
// sol[n][w] = does opt solution to pack items 1..n with weight limit w include item n?
int[][] opt = new int[N + 1][W + 1];
boolean[][] sol = new boolean[N + 1][W + 1];
for (int n = 1; n <= N; n++) {
for (int w = 1; w <= W; w++) {
// don't take item n
int option1 = opt[n - 1][w];
// take item n
int option2 = Integer.MIN_VALUE;
if (weight[n] <= w) {
option2 = profit[n] + opt[n - 1][w - weight[n]];
}
// select better of two options
opt[n][w] = Math.max(option1, option2);
sol[n][w] = (option2 > option1);
}
}
// determine which items to take
boolean[] take = new boolean[N + 1];
for (int n = N, w = W; n > 0; n--) {
if (sol[n][w]) {
take[n] = true;
w = w - weight[n];
} else {
take[n] = false;
}
}
// print results
System.out.println("\nHasil dari set random :");
System.out.println("item" + "\t" + "profit" + "\t" + "berat" +
"\t" + "ambil");
for (int n = 1; n <= N; n++) {
System.out.println(n + "\t" + profit[n] + "\t" + weight[n] +
"\t" + take[n]);
}
int totalProfit = 0, totalBerat = 0;
System.out.print("\nJadi item yang diambil adalah item ");
for (int n = 1; n < N; n++) {
if (take[n]) {
System.out.print(" "+n);
totalProfit+=profit[n];
totalBerat+=weight[n];
}
}
System.out.println("\nDengan total profit "+totalProfit+" dan total berat "+totalBerat);
}
}
Screenshoot
B. Algoritma Kompresi Data Menggunakan Huffman Code a. Definisi Algoritma Huffman
Algoritma Huffman, yang dibuat oleh seorang mahasiswa MIT bernama David Huffman pada tahun 1952, merupakan salah satu metode paling lama dan paling terkenal dalam kompresi teks [2]. Algoritma Huffman menggunakan prinsip pengkodean yang mirip dengan kode Morse, yaitu tiap karakter (simbol) dikodekan hanya dengan rangkaian beberapa bit, dimana karakter yang sering muncul dikodekan dengan rangkaian bit yang pendek dan karakter yang jarang muncul dikodekan.dengan rangkaian bit yang lebih panjang.
Berdasarkan tipe peta kode yang digunakan untuk mengubah pesan awal (isi data yang
diinputkan) menjadi sekumpulan codeword, algoritma Huffman termasuk kedalam kelas
algoritma yang menggunakan metode statik . Metoda statik adalah metoda yang selalu
menggunakan peta kode yang sama, metoda ini membutuhkan dua fase (two-pass): fase
pertama untuk menghitung probabilitas kemunculan tiap simbol dan menentukan peta
kodenya, dan fase kedua untuk mengubah pesan menjadi kumpulan kode yang akan di
taransmisikan.
Sedangkan berdasarkan teknik pengkodean simbol yang digunakan, algoritma Huffman menggunakan metode symbolwise. Metoda symbolwise adalah metode yang menghitung peluang kemunculan dari setiap simbol dalam satu waktu, dimana simbol yang lebih sering muncul diberi kode lebih pendek dibandingkan simbol yang jarang muncul.
b. Pembentukan Pohon Huffman
Kode Huffman pada dasarnya merupakan kode prefiks (prefix code). Kode prefiks adalah himpunan yang berisi sekumpulan kode biner, dimana pada kode prefik ini tidak ada kode biner yang menjadi awal bagi kode biner yang lain. Kode prefiks biasanya direpresentasikan sebagai pohon biner yang diberikan nilai atau label. Untuk cabang kiri pada pohon biner diberi label 0, sedangkan pada cabang kanan pada pohon biner diberi label 1. Rangkaian bit yang terbentuk pada setiap lintasan dari akar ke daun merupakan kode prefiks untuk
karakter yang berpadanan. Pohon biner ini biasa disebut pohon Huffman.
Langkah-langkah pembentukan pohon Huffman adalah sebagai berikut [3] :
1. Baca semua karakter di dalam teks untuk menghitung frekuensi kemunculan setiap karakter. Setiap karakter penyusun teks dinyatakan sebagai pohon bersimpul tunggal.
Setiap simpul di-assign dengan frekuensi kemunculan karakter tersebut.
2. Terapkan strategi algoritma greedy sebagai berikut : gabungkan dua buah pohon yang mempunyai frekuensi terkecil pada sebuah akar. Setelah digabungkan akar tersebut akan mempunyai frekuensi yang merupakan jumlah dari frekuensi dua buah pohon-pohon penyusunnya.
3. Ulangi langkah 2 sampai hanya tersisa satu buah pohon Huffman. Agar pemilihan dua pohon yang akan digabungkan berlangsung cepat, maka semua yang ada selalu terurut menaik berdasarkan frekuensi.
Sebagai contoh, dalam kode ASCII string 7 huruf “ABACCDA” membutuhkan representasi 7 × 8 bit = 56 bit (7 byte), dengan rincian sebagai berikut:
A = 01000001
B = 01000010
A = 01000001 C = 01000011 C = 01000011 D = 01000100 A = 01000001
Pada string di atas, frekuensi kemunculan A = 3, B = 1, C = 2, dan D = 1,
Gambar 1. Pohon H uffman untuk Karakter
“ABACCDA”
c. Proses Encoding
Encoding adalah cara menyusun string biner dari teks yang ada. Proses encoding untuk
satu karakter dimulai dengan membuat pohon Huffman terlebih dahulu. Setelah itu, kode
untuk satu karakter dibuat dengan menyusun nama string biner yang dibaca dari akar
sampai ke daun pohon Huffman.
Langkah-langkah untuk men-encoding suatu string biner adalah sebagai berikut 1. Tentukan karakter yang akan di-encoding
2. Mulai dari akar, baca setiap bit yang ada pada cabang yang bersesuaian sampai ketemu sdaun dimana karakter itu berada
3. Ulangi langkah 2 sampai seluruh karakter diencoding
Sebagai contoh kita dapat melihat tabel dibawah ini, yang merupakan hasil encoding untuk pohon Huffman pada gambar 1
Karakter String Biner Huffman A 0
B 110 C 10 D 111
Tabel 1. Kode Huffman untuk Karakter “ABCD”
d. Proses Decoding
Decoding merupakan kebalikan dari encoding. Decoding berarti menyusun kembali data dari string biner menjadi sebuah karakter kembali. Decoding dapat dilakukan dengan dua cara, yang pertama dengan menggunakan pohon Huffman dan yang kedua dengan menggunakan tabel kode Huffman.
Langkah-langkah men -decoding suatu string biner dengan menggunakan pohon Huffman adalah sebagai berikut :
1. Baca sebuah bit dari string biner.
2. Mulai dari akar
3. Untuk setiap bit pada langkah 1, lakukan traversal pada cabang yang bersesuaian.
4. Ulangi langkah 1, 2 dan 3 sampai bertemu daun. Kodekan rangkaian bit yang telah dibaca dengan karakter di daun.
5. Ulangi dari langkah 1 sampai semua bit di dalam string habis. Sebagai contoh kita akan
men-decoding string biner yang bernilai ”111”
Gambar 2. Proses Decoding dengan Menggunakan Pohon Huffman
setelah kita telusuri dari akar, maka kita akan menemukan bahwa string yang mempunyai kode Huffman “111” adalah karakter D.
Cara yang kedua adalah dengan menggunakan tabel kode Huffman. Sebagai contoh kita akan menggunakan kode Huffman pada Tabel 1 untuk merepresentasikan string
“ABACCDA”. Dengan menggunakan Tabel 1 string tersebut akan direpresentasikan menjadi rangkaian bit : 0 110 0 10 10 1110. Jadi, jumlah bit yang dibutuhkan hanya 13 bit.
Dari Tabel 1 tampak bahwa kode untuk sebuah simbol/karakter tidak boleh menjadi awalan dari kode simbol yang lain guna menghindari keraguan (ambiguitas) dalam proses dekompresi atau decoding. Karena tiap kode Huffman yang dihasilkan unik, maka proses decoding dapat dilakukan dengan mudah. Contoh: saat membaca kode bit pertama dalam rangkaian bit “011001010110”, yaitu bit “0”, dapat langsung disimpulkan bahwa kode bit
“0” merupakan pemetaan dari simbol “A”. Kemudian baca kode bit selanjutnya, yaitu bit
“1”. Tidak ada kode Huffman “1”, lalu baca kode bit selanjutnya, sehingga menjadi “11”.
Tidak ada juga kode Huffman “11”, lalu baca lagi kode bit berikutnya, sehingga menjadi
“110”. Rangkaian kode bit “110” adalah pemetaan dari simbol “B”.
e. Kompleksitas Algoritma Huffman
Algoritma Huffman mempunyai kompleksitas waktu O(n log n), karena dalam melakukan
sekali proses itersi pada saat penggabungan dua buah pohon yang mempunyai frekuensi
terkecil pada sebuah akar membutuhkan waktu O(log n), dan proses itu dilakukan berkali-
kali sampai hanya tersisa satu buah pohon Huffman itu berarti dilakukan sebanyak n kali[4].
f. Contoh Program
/*
* Huffman Algorithm for the DEI's Programming Contest, 2004
* (c) Paulo Marques, 2004.
*
* Note: this program only process text characters:
* ('a'-'z' / 'A'-'Z'). Everything else is ignored.
*/
import java.util.*;
class Node
implements Comparable
{
private int value;
private char content;
private Node left;
private Node right;
public Node(char content, int value)
{
this.content = content;
this.value = value;
}
public Node(Node left, Node right)
{
// Assumes that the left three is always the one that is lowest
this.content = (left.content < right.content) ? left.content : right.content;
this.value = left.value + right.value;
this.left = left;
this.right = right;
}
@Override
public int compareTo(Object arg)
{
Node other = (Node) arg;
// Content value has priority and then the lowest letter
if (this.value == other.value)
return this.content-other.content;
else
return this.value-other.value;
}
////////////////
private void printNode(String path)
{
if ((left==null) && (right==null))
System.out.println(content + " " + path);
if (left != null)
left.printNode(path + '0');
if (right != null)
right.printNode(path + '1');
}
public static void printTree(Node tree)
{
tree.printNode("");
}
}
public class Huffman
{
public static void main(String[] args)
{
Scanner scanner = new Scanner(System.in);
System.out.println("Algoritma Kompresi Data Menggunakan Huffman Code\n");
System.out.print("Masukkan teks asal : ");
String teks = scanner.nextLine();
System.out.println("\nHasil : ");
processFile(teks);
}
private static void processFile(String fileContents)
{
int[] frequency = new int['Z'-'A'+1]; //
Frequency table of each letter
TreeSet<Node> trees = new TreeSet<Node>(); // List containing all trees -- ORDERED!
// Build the frequency table of each letter
for (int i=0; i<fileContents.length(); i++)
{
char ch =
Character.toUpperCase(fileContents.charAt(i));
if ((ch >= 'A') && (ch <= 'Z'))
++frequency[ch - 'A'];
}
// Build up the initial trees
for (int i=0; i<'Z'-'A'+1; i++)
{
if (frequency[i] > 0)
{
Node n = new Node((char)('A'+i), frequency[i]);
trees.add(n);
}
}
// Huffman algoritm
while (trees.size() > 1)
{
Node tree1 = (Node) trees.first();
trees.remove(tree1);
Node tree2 = (Node) trees.first();
trees.remove(tree2);
Node merged = new Node(tree1, tree2);
trees.add(merged);
}
// Print the resulting tree
if (trees.size() > 0)
{
Node theTree = (Node) trees.first();
Node.printTree(theTree);
}
else
System.out.println("The file didn't contain useful characters.");
}
}
Screenshoot
C. Algoritma Minimum Spanning Tree
a. Definisi Algoritma Minimum Spanning Tree
Definisi dari Spanning tree Untuk suatu jaringan dengan n node, spanning tree adalah sekumpulan dari n-1 arc yang menghubungkan semua node dalam jaringan dan tidak mengandung loop sedangkan definisi dari Minimum Spanning Tree sendiri adalah spanning tree dengan panjang minimum dalam suatu jaringan.
Pohon Merentang Minimum (Minimum Spanning Tree) Jika G pada gambar 2.10 merupakan graf berbobot, maka bobot pohon merentang T
1
atau T
2
didefinisikan sebagai jumlah bobot semua sisi di T
1
atau T
2
. Diantara pohon merentang yang ada pada G, yang
paling penting adalah pohon merentang dengan jumlah bobot sisi e minimum. Pohon
merentang dengan jumlah bobot sisi e minimum ini disebut dengan pohon merentang minimum atau Minimum Spanning Tree (MST). Contoh aplikasi MST yang digunakan dalam penulisan skripsi ini adalah masalah pemasangan jaringan kabel listrik menggunakan graf. MST digunakan untuk memilih jalur dengan jumlah bobot terkecil yang akan
meminimalkan biaya pemasangan kabel listrik
Gambar 2.10. G adalah Graf Berbobot, T
1
dan T
2
adalah Pohon Merentang Berbobot dari Graf G.
Dari graf berbobot G, kita harus menentukan pohon merentang mana yang paling minimum.
Apakah T
1
atau T
2
, hal tersebut yang akan dicari dengan membangun pohon merentang yang mempunyai jumlah jalur terpendek, dengan kata lain harus dicari pohon merentang minimum. Cara yang paling sederhana adalah dengan mendaftarkan semua pohon merentang berbobot yang mungkin dibuat (dalam hal ini T
1dan T
2) dan menghitung total bobot tiap-tiap pohon merentang. Selanjutnya dipilih pohon merentang dengan total bobot sisi e yang paling kecil. Metode ini tidak efisien, terutama pada graf cukup besar karena terdapat banyak sekali pohon merentang yang dapat dibuat.
Algoritma Prim
Pada tahun 1956 seorang computer scientist Robert C Prim berhasil menyusun algoritma untuk membuat pohon merentang minimum secara efisien. Algoritma Prim membentuk MST langkah per langkah. Pada setiap langkah dipilih sisi e dari graf G yang mempunyai bobot minimum dan bersisian dengan simpul-simpul di dalam T tetapi e tidak membentuk sirkuit didalam T. Ada 3 (tiga) langkah yang dilakukan pada algoritma Prim, yaitu :
1. Pilih sisi graf G yang berbobot paling minimum dan masukkan ke dalam T
2. Pilih sisi e yang mempunyai bobot minimum dan bersisian dengan simpul di T, tetapi e
tidak membentuk sirkuit di T, lalu masukkan e ke dalam T.
3. Ulangi langkah ke-dua sebanyak n-2 kali.
Jumlah langkah seluruhnya didalam algoritma Prim adalah 1 + ( n – 2 ) = n - 1 yaitu sebanyak jumlah sisi didalam pohon merentang dengan n buah simpul.
b. Contoh Program
import java.io.*;
import java.util.Scanner;
class Prim {
public static Scanner sc = new Scanner(System.in);
static int[][] G;
static int[][] t;
static int[] near;
static int n;
static int mincost = 0;
static int k, l;
static void prims() {
MinKL();
mincost = G[k][l];
t[1][1] = l;
t[1][2] = k;
for (int i = 1; i <= n; i++) {
near[i] = (G[i][l] < G[i][k]) ? l : k;
}
near[k] = near[l] = 0;
for (int i = 2; i < n; i++) {
int j = Min();
t[i][1] = j;
t[i][2] = near[j];
mincost = mincost + G[j][near[j]];
near[j] = 0;
for (int k = 1; k <= n; k++) {
if ((near[k] != 0) && G[k][ near[k]] > G[k][j]) {
near[k] = j;
}
}
}
}
static int Min() {
int j = 1;
for (int i = 1; i <= n; i++) {
if (near[i] != 0) {
j = i;
break;
}
}
for (int i = 1; i <= n; i++) {
if (near[i] != 0) {
if (G[j][near[j]] > G[i][near[i]]) {
j = i;
}
}
}
return j;
}
static void MinKL() {
int k1 = 1, l1 = 2;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if ((i != j) && (i < j)) {
if ((G[i][j] < G[k1][l1]) && G[i][j] != 0) {
k1 = i;
l1 = j;
}
}
}
}
if (G[k1][l1] != 0) {
k = k1;
l = l1;
}
}
public static void main(String[] args) throws IOException {
System.out.println("Algoritma Minimum Spanning Tree Prim");
System.out.print("\nMasukkan jumlah verteks: ");
n = Integer.parseInt(sc.nextLine());
G = new int[n + 1][n + 1];
t = new int[n + 1][3];
near = new int[n + 1];
System.out.print("\nMasukkan bobot lintasan :\n");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if ((i != j) && (i < j)) {
System.out.print(i + " and " + j + ": ");
G[j][i] = G[i][j] = Integer.parseInt(sc.nextLine());
if (G[i][j] == 0) {
G[j][i] = G[i][j] = 7001;
}
}
if (i == j) {
G[i][j] = 7001;
}
}
}
prims();
System.out.println("\nHasil :");
for (int i = 1; i <= n; i++) {
if ((t[i][1] != 0) && (t[i][2] != 0)) {
System.out.println(t[i][1] + "-" + t[i][2]);
}
}
System.out.println("\nMinimum bobot : " + mincost);
}
}