diff --git a/README.md b/README.md
index f77e0e810edfc34916acba1e68f804cc665adacd..1577b54bc39e270f3c26bed272b0e23984ac83fc 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,89 @@
-# Announcement
+<h1 align="center">
+    <b>
+        <br>
+        # Tugas Besar 2 IF3230 Sistem Paralel dan Terdistribusi
+        <br>
+    </b>
+</h1>
 
-Beberapa file yang harus ada dalam repositori tersebut diantaranya:
-* Direktori src yang berisi source code yang anda buat.
-* File output yang berisi hasil uji dijkstra algorithm pada data uji.
-* Makefile. Buatlah sehingga kompilasi program dapat dilakukan hanya dengan pemanggilan command ’make’ saja.
-* File README.md yang berisi:
-    * Petunjuk penggunaan program.
-    * Pembagian tugas. Sampaikan dalam list pengerjaan untuk setiap mahasiswa. Sebagai contoh: XXXX mengerjakan fungsi YYYY, ZZZZ, dan YYZZ.
-    * Laporan pengerjaan, dengan struktur laporan sesuai dengan deskripsi pada bagian sebelumnya.
+<h2 align="center">
+    <b>
+        <br>
+        OpenMP - Dijkstra Algorithm
+        <br>
+        <br>
+    </b>
+</h2>
 
+## Petunjuk Penggunaan Program
+* Compile: <br>
+  ketikan ```make``` pada direktori tempat ```makefile``` berada
+* Run: <br>
+  ketikan ```run``` pada direktori tempat ```makefile``` berada
+
+## Laporan Pengerjaan
+### Deskripsi Solusi Paralel
+Solusi paralel yang dilakukan adalah data parallelism karena data yang ada dibagi-bagi ke *thread* yang ada, sehingga *thread* pusat hanya bertugas untuk menerima hasil dari pemrosesan algoritma dijkstra yang dilakukan oleh *thread* lain. Hasil pemrosesan algoritma dijkstra merupakan satu baris dari matriks jarak antar node. <br>
+<div align="center">
+    <img src="./assets/data_task_parallelism.png" width="300" height="200"/>
+</div>
+
+Cara kerja program:
+1. Program menginisiasi graf dalam bentuk matriks berukuran N x N
+2. Untuk setiap baris dan kolom, program mengisi nilai *random* yang didapat dari funsi ```rand()``` dengan seed ```13517020``` atau ```13517137```
+3. Program mulai menjalankan algoritma dijkstra untuk mencari nilai cost minimum yang dibutuhkan dari node-x untuk mencapai node-y
+   * Jika jumlah *thread* yang digunakan hanya 1, program akan menjalankan algoritma dijkstra secara serial
+   * Jika jumlah *thread* yang digunakan lebih dari 1, program akan menjalankan algoritma dijkstra secara paralel
+     * *thread* dengan nilai ```rank = 0``` menerima hasil pemrosesan graf menggunakan algoritma dijkstra dari *thread-thread* lain
+     * *thread* dengan nilai ```rank ≠ 0``` melakukan pemrosesan graf menggunakan algoritma dijkstra untuk dikirimkan ke *thread* dengan nilai ```rank = 0```
+
+### Analisis Solusi
+* Kelebihan:
+  * Setiap *thread* membaca dari satu memory yang sama
+  * Jika *thread* yang digunakan hanya 1 program akan langsung menjalankan algoritma dijkstra secara serial
+  * Lebih hemat *memory space* karena alokasi *memory* menyesuaikan input jumlah nodes
+* Kelemahan:
+  * Karena menggunakan satu server, perbedaan waktu yang dibutuhkan antara 1 *thread*, 2 *thread*, 3 *thread*, dst. tidak berbeda jauh
+* Solusi yang lebih baik:
+  * Dapat menggunakan beberapa server tetapi disaat yang bersamaan masih dapat mengakses *memory* yang sama
+
+### Jumlah Thread yang Digunakan
+6 *thread* karena dari hasil percobaan kami, waktu yang dibutuhkan untuk mendapatkan solusi dengan menggunakan 6 thread jauh lebih cepat dibandingkan jika menggunakan 5 thread, 4 thread, 3 thread, 2 thread dan 1 thread (serial). Hal ini disebabkan oleh jumlah data yang dibagi untuk setiap thread menurun sesuai dengan banyaknya thread yang digunakan sehingga thread dapat menyelesaikan tugasnya lebih cepat.
+<div align="center">
+    <img src="./assets/data_parallelism.png" width="300" height="200"/>
+</div>
+
+### Pengukuran Kinerja Algoritma Paralel dengan Serial
+| Jumlah Thread | Jumlah Node |  Waktu 1 (μs) |  Waktu 2 (μs) |  Waktu 3 (μs) |
+|:-------------:|:-----------:|:-------------:|:-------------:|:-------------:|
+|   1 (Serial)  |         100 |     11809.000 |     11341.000 |     11738.000 |
+|   1 (Serial)  |         500 |   1330483.000 |   1336266.000 |   1346888.000 |
+|   1 (Serial)  |        1000 |  11306142.000 |  11269185.000 |  11353796.000 |
+|   1 (Serial)  |        3000 | 328869828.000 | 322524927.000 | 320788807.000 |
+|   2 (Paralel) |         100 |      8630.000 |      8863.000 |      9170.000 |
+|   2 (Paralel) |         500 |   1344506.000 |   1341028.000 |   1353119.000 |
+|   2 (Paralel) |        1000 |  11188346.000 |  11266470.000 |  11314343.000 |
+|   2 (Paralel) |        3000 | 326371659.000 | 322214533.000 | 324375813.000 |
+|   3 (Paralel) |         100 |     11494.000 |     12541.000 |     13622.000 |
+|   3 (Paralel) |         500 |   1315593.000 |   1350490.000 |   1337863.000 |
+|   3 (Paralel) |        1000 |  11335433.000 |  11406718.000 |  11197439.000 |
+|   3 (Paralel) |        3000 | 329445759.000 | 323444526.000 | 379086253.000 |
+|   4 (Paralel) |         100 |     11883.000 |     11533.000 |     12161.000 |
+|   4 (Paralel) |         500 |   1339848.000 |   1339332.000 |   1344472.000 |
+|   4 (Paralel) |        1000 |  11513116.000 |  11305632.000 |  11336602.000 |
+|   4 (Paralel) |        3000 | 328357001.000 | 324471460.000 | 323581156.000 |
+|   5 (Paralel) |         100 |     12112.000 |     11359.000 |     11571.000 |
+|   5 (Paralel) |         500 |   1335812.000 |   1341126.000 |   1363780.000 |
+|   5 (Paralel) |        1000 |  11310832.000 |  11268102.000 |  11176265.000 |
+|   5 (Paralel) |        3000 | 323646028.000 | 328808488.000 | 383983323.000 |
+|   6 (Paralel) |         100 |     11432.000 |     11358.000 |     11560.000 |
+|   6 (Paralel) |         500 |   1342867.000 |   1371984.000 |   1333992.000 |
+|   6 (Paralel) |        1000 |  11332027.000 |  11301639.000 |  11337420.000 |
+|   6 (Paralel) |        3000 | 321272669.000 | 324136484.000 | 323526201.000 |
+
+### Analisis Perbandingan Kinerja Serial dan Paralel
+Algoritma dijkstra yang dijalankan secara serial memakan waktu tidak jauh berbeda dibandingkan dengan algoritma dijkstra yang dijalankan secara paralel karena jumlah server yang digunakan sama antara serial dengan paralel.
+
+## Pembagian Tugas
+* 13517020 mengerjakan convert fungsi algoritma dijkstra openMPI to openMP, makefile dan laporan
+* 13517137 mengerjakan convert fungsi algoritma dijkstra openMPI to openMP, makefile dan laporan
\ No newline at end of file
diff --git a/assets/data_parallelism.png b/assets/data_parallelism.png
new file mode 100644
index 0000000000000000000000000000000000000000..9285b180897c59461cf96ac1aeb6924c3e8611dd
Binary files /dev/null and b/assets/data_parallelism.png differ
diff --git a/assets/data_task_parallelism.png b/assets/data_task_parallelism.png
new file mode 100644
index 0000000000000000000000000000000000000000..53b0e1cf654a3260b244a4c6f164416be8f1b2d6
Binary files /dev/null and b/assets/data_task_parallelism.png differ
diff --git a/copy.sh b/copy.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2fda7219f9dbb1a5a41a35f9cd4d1176a4289294
--- /dev/null
+++ b/copy.sh
@@ -0,0 +1,4 @@
+ssh 13517020@167.205.37.150 'mkdir -p src'
+ssh 13517137@167.205.37.150 'mkdir -p src'
+scp $1 13517020@167.205.35.150:~/src
+scp $1 13517137@167.205.35.150:~/src
diff --git a/makefile b/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..09ca8c21f4dfb26329e9fcdb1bb780662344ae69
--- /dev/null
+++ b/makefile
@@ -0,0 +1,7 @@
+_OBJ = omp_dijkstra
+
+make:
+	gcc -g -Wall -o $(_OBJ) src/$(_OBJ).c -fopenmp
+
+run:
+	./$(_OBJ) 100 6
\ No newline at end of file
diff --git a/out/matrix3000.txt b/out/matrix3000.txt
new file mode 100644
index 0000000000000000000000000000000000000000..45863454b88c1007b9c96fd265de5ea75952cb0d
Binary files /dev/null and b/out/matrix3000.txt differ
diff --git a/out/result3000.txt b/out/result3000.txt
new file mode 100644
index 0000000000000000000000000000000000000000..49f256d17b3d98658d9ccd02d5e6ac6ce85a89ed
Binary files /dev/null and b/out/result3000.txt differ
diff --git a/src/omp_dijkstra.c b/src/omp_dijkstra.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b5fe8ae768d51826a3cc9e687034af7462bb289
--- /dev/null
+++ b/src/omp_dijkstra.c
@@ -0,0 +1,207 @@
+// Copyright www.computing.llnl.gov
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <omp.h>
+#include <assert.h>
+#include <time.h>
+
+int minDistance(long dist[], bool sptSet[], long V)
+{
+    // Initialize min value
+    int min = INT_MAX, min_index;
+
+    for (int v = 0; v < V; v++)
+    {
+        if ((sptSet[v] == false) && (dist[v] <= min))
+        {
+            min = dist[v], min_index = v;
+        }
+    }
+
+    return min_index;
+}
+
+void dijkstra(long src, long V, long **graph, long *dist)
+{
+    // sptSet[i] will be true if vertex i is included in shortest path tree or shortest distance from src to i is finalized
+    bool sptSet[V];
+
+    // Initialize all distances as INFINITE and stpSet[] as false
+    for (int i = 0; i < V; i++)
+    {
+        dist[i] = INT_MAX, sptSet[i] = false;
+    }
+
+    // Distance of source vertex from itself is always 0
+    dist[src] = 0;
+
+    // Find shortest path for all vertices
+    for (int count = 0; count < V - 1; count++)
+    {
+        // Pick the minimum distance vertex from the set of vertices not yet processed. u is always equal to src in the first iteration.
+        int u = minDistance(dist, sptSet, V);
+
+        // Mark the picked vertex as processed
+        sptSet[u] = true;
+
+        // Update dist value of the adjacent vertices of the picked vertex.
+        for (int v = 0; v < V; v++)
+        {
+            // Update dist[v] only if is not in sptSet, there is an edge from u to v, and total weight of path from src to  v through u is smaller than current value of dist[v]
+            if (!sptSet[v] && graph[u][v] && (dist[u] != INT_MAX) && (dist[u] + graph[u][v] < dist[v]))
+            {
+                dist[v] = dist[u] + graph[u][v];
+            }
+        }
+    }
+}
+
+void solution(long **matrix, long **newmatrix, long nodes);
+
+int main(int argc, char *argv[])
+{
+    // Set rand() seed
+    srand(13517020);
+    /* total cost == 0
+     size | total
+     100  |    0
+     500  |    4
+     1000 |   18
+     3000 |  135
+     5000 |  380
+ */
+    // srand(13517137);
+    /* total cost == 0
+     size | total
+     100  |    0
+     500  |    2
+     1000 |   13
+     3000 |  126
+     5000 |  360
+   */
+
+    if (argc < 3)
+    {
+        fprintf(stderr, "error: missing command line arguments\n");
+        exit(1);
+    }
+    else
+    {
+        // Inititate graph
+        long nodes = atoi(argv[1]);
+        int thread_count = strtol(argv[2], NULL, 10);
+        long **matrix = (long **)malloc(nodes * sizeof(long *));
+
+        for (int i = 0; i < nodes; i++)
+        {
+            matrix[i] = (long *)malloc(nodes * sizeof(long));
+        }
+
+        assert(matrix != NULL);
+
+        // Build graph
+        for (int i = 0; i < nodes; i++)
+        {
+            for (int j = 0; j < nodes; j++)
+            {
+                if (i == j)
+                {
+                    matrix[i][j] = 0;
+                }
+                else
+                {
+                    matrix[i][j] = rand();
+                }
+            }
+        }
+
+        long **newmatrix = (long **)malloc(nodes * sizeof(long *));
+
+        for (int i = 0; i < nodes; i++)
+        {
+            newmatrix[i] = (long *)malloc(nodes * sizeof(long));
+        }
+
+// Dijkstra Algorithm
+// MPI_Status Stat;
+// MPI_Init(NULL, NULL);
+// MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
+// MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#pragma omp parallel num_threads(thread_count)
+        solution(matrix, newmatrix, nodes);
+
+        // Dealocation
+        for (int i = 0; i < nodes; i++)
+        {
+            free(matrix[i]);
+        }
+
+        free(matrix);
+
+        for (int i = 0; i < nodes; i++)
+        {
+            free(newmatrix[i]);
+        }
+
+        free(newmatrix);
+    }
+    return 0;
+}
+
+void solution(long **matrix, long **newmatrix, long nodes)
+{
+    clock_t begin = clock();
+    int numtasks, rank = 1;
+    rank = omp_get_thread_num();
+    numtasks = omp_get_num_threads();
+
+    for (int i = rank; i < nodes; i += numtasks)
+    {
+        dijkstra(i, nodes, matrix, newmatrix[i]);
+        // printf("Completing part %d with processor %d\n", i, rank);
+        // MPI_Send(newmatrix[i], nodes, MPI_INT, 0, i, MPI_COMM_WORLD);
+    }
+
+#pragma omp barrier
+
+    if (rank == 0)
+    {
+        clock_t end = clock();
+        // printf("Printing to file");
+        // Write to file
+        FILE *fp;
+        fp = fopen("old_matrix.txt", "w");
+        fprintf(fp, "Old matrix:\n");
+
+        for (int i = 0; i < nodes; i++)
+        {
+            for (int j = 0; j < nodes; j++)
+            {
+                fprintf(fp, "%ld ", matrix[i][j]);
+            }
+
+            fprintf(fp, "\n");
+        }
+
+        fclose(fp);
+
+        fp = fopen("result.txt", "w");
+        fprintf(fp, "New matrix:\n");
+
+        for (int i = 0; i < nodes; i++)
+        {
+            for (int j = 0; j < nodes; j++)
+            {
+                fprintf(fp, "%ld ", newmatrix[i][j]);
+            }
+
+            fprintf(fp, "\n");
+        }
+
+        fprintf(fp, "Solution found in: %.3f microseconds\n", ((double)(end - begin) / CLOCKS_PER_SEC) * 1000000);
+        printf("Solution found in: %.3f microseconds\n", ((double)(end - begin) / CLOCKS_PER_SEC) * 1000000);
+        fclose(fp);
+    }
+}
\ No newline at end of file