diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..c8a4e6465edbb955cc465e35f1c7340cfb2ed9bb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,18 @@
+serial: ./src/serial.c ./src/dijkstra.* ./src/util.*
+	gcc ./src/serial.c ./src/dijkstra.c ./src/util.c -o ./bin/serial
+	./bin/serial $(n)
+
+parallel: ./src/paralel.c ./src/util.* ./src/dijkstra.*
+	mpicc ./src/paralel.c ./src/util.c ./src/dijkstra.c -o ./bin/parallel
+	mpirun -np $(np) --hostfile mpi_hostfile ./bin/parallel $(np) $(nv)
+
+run_par: ./bin/parallel
+	mpirun -np $(np) --hostfile mpi_hostfile ./bin/parallel $(np) $(nv)
+
+hello_omp: ./src/hello_openmp.c
+	gcc -g -Wall -fopenmp -o ./bin/hello_omp ./src/hello_openmp.c
+	./bin/hello_omp $(nt)
+
+parallel_omp: ./src/paralel_openmp.c
+	gcc -g -Wall -fopenmp -o ./bin/parallel_omp ./src/paralel_openmp.c ./src/util.c ./src/dijkstra.c
+	./bin/parallel_omp $(nt) $(nv)
\ No newline at end of file
diff --git a/src/boolean.h b/src/boolean.h
new file mode 100644
index 0000000000000000000000000000000000000000..652f1a7460078e4fbea6ecaae9eb8923553ea768
--- /dev/null
+++ b/src/boolean.h
@@ -0,0 +1,8 @@
+#ifndef _BOOLEAN_h
+#define _BOOLEAN_h
+
+#define bool unsigned char
+#define true 1
+#define false 0
+
+#endif
\ No newline at end of file
diff --git a/src/dijkstra.c b/src/dijkstra.c
new file mode 100644
index 0000000000000000000000000000000000000000..7662d2c56f457ecc5cd96940b09267e49eedbce3
--- /dev/null
+++ b/src/dijkstra.c
@@ -0,0 +1,117 @@
+#include "dijkstra.h"
+
+
+/**
+ * Get vertex index with minimum distance which not yet included
+ * in spt_set
+ * @param  dist    distance from origin vertex to vertex with that index
+ * @param  spt_set a set denoting vertices included in spt_set
+ * @param n number of vertices in the graph
+ * @return         index of minimum distance not yet included in spt_set
+ */
+int min_distance_idx(long dist[], bool spt_set[], int n) {
+	// Initialize min value 
+    int min = INT_MAX, min_index; 
+  
+    for (int i = 0; i < n; i++) {
+    	if (spt_set[i] == false && dist[i] <= min) {
+    		min = dist[i];
+    		min_index = i;
+    	}
+    } 
+        
+  
+    return min_index; 
+}
+
+
+/**
+ * generate a graph with n vertices
+ * @param  n number of vertices
+ * @return   2D array, graph[i][j] = graph[j][i] = distance from vertex i to j
+ */
+long **gen_graph(int n) {
+	// alokasi memori untuk matriks yang merepresentasikan graf
+	long **result = (long **)malloc(n * sizeof(long *)); 
+    for (int i = 0; i < n; i++) {
+    	result[i] = (long *)malloc(n * sizeof(long)); 
+    }    
+  
+    // isi matriks dengan bilangan random
+    srand(13517122);
+    
+    for (int i = 0; i < n; i++) {
+    	for (int j = i; j < n; j++) {
+    		if (i == j) {
+    			result[i][j] = 0;
+    		} else {
+    			result[i][j] = result[j][i] = rand();	
+    		}
+    		
+    	}
+    }
+     
+ 	return result; 
+}
+
+long **gen_temp(int r, int c) {
+	// alokasi memori untuk matriks yang merepresentasikan graf
+	long **result = (long **)malloc(r * sizeof(long *)); 
+	// printf("[gen_temp] initiate temp\n");
+    for (int i = 0; i < r; i++) {
+    	result[i] = (long *)malloc(c * sizeof(long)); 
+    	// printf("[gen_temp] initiate each row in temp\n");
+    }    
+    
+    for (int i = 0; i < r; i++) {
+    	for (int j = 0; j < c; j++) {
+    		// printf("[gen_temp] filling temp\n");
+    		result[i][j] = 0;
+    	}
+    }
+     
+ 	return result; 
+}
+
+
+long *dijkstra(long **graph, int n, int src) {
+
+	// output array, contains shortest distance from src to every vertices
+	long *dist = (long *) malloc (sizeof(long) * n);
+	// spt_set[i] is true if vertex i already included in the shortest path tree
+	bool spt_set[n];
+
+	// initialize dist and spt_set
+	for (int i = 0; i < n; i++) {
+		dist[i] = INT_MAX;
+		spt_set[i] = false;
+	}
+
+	// initiate path searching 
+	dist[src] = 0;
+
+
+	// find the shortest path for all vertices
+	for (int i = 0; i < n; i++) {
+
+		// pick vertex with minimum distance from src from spt_set not yet
+		// processed
+		int processed_vertex = min_distance_idx(dist, spt_set, n);
+
+		// mark vertex as processed
+		spt_set[processed_vertex] = true;
+
+		for (int j = 0; j < n; j++) {
+			// check vertices connected to processed_vertex not yet processed
+			if (!spt_set[j] 
+				&& graph[processed_vertex][j] != 0
+				&& dist[processed_vertex] != INT_MAX 
+				&& dist[processed_vertex] + graph[processed_vertex][j] < dist[j]) {
+
+				dist[j] = dist[processed_vertex] + graph[processed_vertex][j];
+			}
+		}
+	}
+
+	return dist;
+}
\ No newline at end of file
diff --git a/src/dijkstra.h b/src/dijkstra.h
new file mode 100644
index 0000000000000000000000000000000000000000..00a7aca177e1a11036ba31fc848d36cd817a2e2c
--- /dev/null
+++ b/src/dijkstra.h
@@ -0,0 +1,43 @@
+#ifndef DIJKSTRA_H
+#define DIJKSTRA_H
+#include <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include "boolean.h"
+
+/**
+ * Get vertex index with minimum distance which not yet included
+ * in spt_set
+ * @param  dist    distance from origin vertex to vertex with that index
+ * @param  spt_set a set denoting vertices included in spt_set
+ * @return         index of minimum distance not yet included in spt_set
+ */
+int min_distance_idx(long dist[], bool spt_set[], int n);
+
+
+/**
+ * generate a graph with n vertices
+ * @param  n number of vertices
+ * @return   2D array, graph[i][j] = graph[j][i] = distance from vertex i to j
+ */
+long **gen_graph(int n);
+
+
+/**
+ * generate 2D array with dimension of r x c
+ * @param  r number of rows
+ * @param c number of columns
+ * @return   2D array, all filled with zero
+ */
+long **gen_temp(int r, int c);
+
+/**
+ * 
+ * @param graph [description]
+ * @param n     [description]
+ * @param src   [description]
+ */
+long *dijkstra(long **graph, int n, int src);
+
+
+#endif
\ No newline at end of file
diff --git a/src/hello_openmp.c b/src/hello_openmp.c
new file mode 100644
index 0000000000000000000000000000000000000000..904804a7ab8d2658b6e70ffcfc6366bd78b519ae
--- /dev/null
+++ b/src/hello_openmp.c
@@ -0,0 +1,20 @@
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int main (int argc, char *argv[]) {
+    int nthreads = atoi(argv[1]), t_id;
+    int i;
+    #pragma omp parallel for private(t_id) 
+        for (i = 0; i < 10; i++) {
+            t_id = omp_get_thread_num(); // get thread if for each thread
+            printf("i : %d, by the way i'm thread %d\n", i, t_id);
+        }
+
+        // printf("Hello from thead number %d of %d\n", t_id, nthreads);
+
+
+
+
+    return 0;
+}
\ No newline at end of file
diff --git a/src/hellompi.c b/src/hellompi.c
new file mode 100644
index 0000000000000000000000000000000000000000..4753d877043ff48859456bccb6ca9e3bc36e0bf7
--- /dev/null
+++ b/src/hellompi.c
@@ -0,0 +1,103 @@
+#include <mpi.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc,char *argv[]) {
+  int numtasks, rank;
+  char processor_name[MPI_MAX_PROCESSOR_NAME];
+  int name_len;
+  int arr_size = 3;
+
+
+  MPI_Status Stat;
+  MPI_Init(&argc,&argv);
+  MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  MPI_Get_processor_name(processor_name, &name_len);
+  // printf("Hello from processor %s, task %d of %d, argv[1]: %s\n",
+  // processor_name, rank, numtasks, argv[1]);
+  // 
+  
+  int *result_arr = (int *) malloc(arr_size * numtasks * sizeof(int));
+  // int **local_mat = (int **) malloc(arr_size * sizeof(int*));
+  int *local_arr = (int *) malloc(arr_size * sizeof(int));
+  
+  // for (int i = 0; i < arr_size; i++) {
+  //   local_mat = (int*) malloc(5 *sizeof(int));
+  // }
+  
+  // for (int i = 0; i < r; i++) {
+  //     for (int j = i; j < c; j++) {
+  //       local_mat[i][j] = local_mat[j][i] = 0;
+  //     }
+  // }  
+
+  for (int i = 0; i < arr_size; i++) {
+    local_arr[i] = i*rank*3;
+  }
+
+  if (rank == 0) {
+    // int **local_mat = (int **) malloc(arr_size * sizeof(int*));
+    
+    int *temp = (int *) malloc(arr_size * sizeof(int));
+    
+
+
+    // initiate result arr
+    for (int i = 0; i < arr_size; i++) {
+      result_arr[i] = local_arr[i];
+    }
+
+    // terima array dari tiap node
+    for (int i = 1; i < numtasks; i++) {
+      MPI_Recv( temp, 
+              arr_size*sizeof(int), 
+              MPI_INT, 
+              i,
+              0,
+              MPI_COMM_WORLD,
+              MPI_STATUS_IGNORE
+              );
+      // salin array ke result_arr
+      // result_arr[i*arr_size] = temp;
+      memcpy(result_arr+(arr_size*i),
+             temp,
+             arr_size* sizeof(int)
+             );
+      
+      
+      
+      // for (int j = 0; j < arr_size && j+(rank*arr_size); j++) {
+      //   result_arr[j+i*arr_size] = temp[j];
+      // }
+      // 
+      // printf("array from node %d\n", i);
+      // for(int j = 0; j < arr_size; j++) {
+      //   printf("%d ", temp[j]);
+      // }
+      // printf("\n");
+    }
+  } else {
+    MPI_Send( local_arr,
+              arr_size*sizeof(int),
+              MPI_INT,
+              0,
+              0,
+              MPI_COMM_WORLD
+              );
+  }
+
+  if (rank == 0) {
+    printf("here is the array you ordered\n");
+    for (int i=0; i<arr_size*numtasks; i++){
+      printf("%d ", result_arr[i]);
+    }
+    printf("\n");
+  }
+  
+  free(local_arr);
+  free(result_arr);
+
+  MPI_Finalize();
+} 
diff --git a/src/paralel.c b/src/paralel.c
new file mode 100644
index 0000000000000000000000000000000000000000..0dea0f60ea42163534396360e9082d71f660e1fb
--- /dev/null
+++ b/src/paralel.c
@@ -0,0 +1,186 @@
+#include "dijkstra.h"
+#include "util.h"
+#include <stdio.h>
+#include <mpi.h>
+#include <math.h>
+#include <string.h>
+
+
+int main(int argc, char *argv[])
+{
+	int numprocs, rank;
+	char processor_name[MPI_MAX_PROCESSOR_NAME];
+	int name_len;
+
+	int np = atoi(argv[1]);
+	int numvertices = atoi(argv[2]);
+	int chunk_size = ceil(numvertices/np);
+	// printf("chunk_size : %d\n", chunk_size);
+	// printf("np : %d\n", np);
+	// printf("numvertices : %d\n", numvertices);
+
+
+	MPI_Status Stat;
+	MPI_Init(&argc,&argv);
+	MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
+	MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+	MPI_Get_processor_name(processor_name, &name_len);
+
+
+	double start_time, finish_time;
+
+	// generate graph
+	// printf("about to generate our graph\n");
+	long **graph = gen_graph(numvertices);
+
+	// start the timer
+	MPI_Barrier(MPI_COMM_WORLD);
+	start_time = MPI_Wtime();
+
+
+	// set chunk size and local src
+	// int my_first_src = rank * ceil(numvertices/numprocs);
+	// int my_last_src = my_first_src + chunk_size;
+	int my_first_src = rank * chunk_size;
+	// int my_last_src = if (my_first_src+chunk_size < numvertices)? my_first_src+chunk_size:;
+
+	if (rank == 0) {
+		printf("chunk_size : %d\n", chunk_size);
+	}
+	printf("i'm node %d, my_first_src: %d\n", rank, my_first_src);	
+	// printf("i'm node %d, my_last_src: %d\n", rank, my_last_src);	
+
+
+
+	// long **my_results = (long **) malloc(chunk_size * sizeof(long*));
+	// allocate 2D array for local result
+	// printf("initiate my result\n");
+	long **my_results = gen_temp(chunk_size, numvertices);
+	// printf("done initiating my result\n");
+
+	// find shortest path from each src
+	for (int i = 0; i+my_first_src < numvertices && i < chunk_size; i++) {
+		// printf("i'm node %d and currently working on row %d \n", rank, i+my_first_src);
+		long *dist = dijkstra(graph, numvertices, i+my_first_src);
+		my_results[i] = dist;
+	}
+	// printf("hi i'm node %d and i'm done searching\n", rank);
+
+
+	// TBD gathering data from these processes
+	if ( rank == 0 ) { // gather data from other nodes
+		long **result = gen_temp(numvertices, numvertices);
+		// printf("generated empty result matrix\n");
+		// long **temp = gen_temp(chunk_size, numvertices);
+		long *temp = (long*) malloc(numvertices * sizeof(long));
+		// printf("generated temp\n");
+
+		memcpy(result,
+				my_results,
+				chunk_size*sizeof(long*));
+		printf("copying temp to result\n");
+
+		for (int i = 1; i < numprocs; i++) {
+			printf("about to receive local result from node %d\n", i);
+
+			for (int j = 0; j < chunk_size; j++) { // loop buat nerima tiap baris dari node lain
+				MPI_Recv(temp,
+						 numvertices*sizeof(long),
+						 MPI_LONG,
+						 i,
+						 0,
+						 MPI_COMM_WORLD,
+						 MPI_STATUS_IGNORE);
+				// for (int i=0;i<numvertices;i++) {
+				// 	printf("%d ", temp[i]);
+				// }
+				// printf("\n");
+				// printf("alamat result yang mau ditulis: result+ %d\n", (i*chunk_size)+(j*numvertices));
+				// memcpy(result+((i*chunk_size)+(j*numvertices)),
+				// 	    temp,
+				// 	    chunk_size*sizeof(long));
+				for (int k = 0; k < numvertices; k++) {
+					result[i*chunk_size+j][k] = temp[k];
+				}
+					
+
+			}
+
+			printf("done receiving local result from node %d\n", i);
+
+			// for (int i =0; i < chunk_size; i++) {
+			// 	for (int j= 0 ; j < numvertices; j++){
+			// 		printf("%ld ", temp[i][j]);
+			// 	}
+			// 	printf("\n");
+			// }
+			printf("copying local result from node %d to result\n", i);
+				
+
+		}
+
+		// for (int i=0; i < numvertices; i++) {
+		// 	printf("row %d\n", i);
+		// 	for (int j = 0; j < numvertices; j++) {
+		// 		printf("%d ", result[i][j]);
+		// 	}
+		// 	printf("\n");
+		// }
+		// 
+
+		char filename[20];
+		sprintf(filename, "./output_parallel_%d", numvertices);
+		printf("about to write output file\n");
+		write_result(result, numvertices, filename);
+		printf("done writing\n");
+
+		//free result (2d arr)
+		for(int i = 0; i < numvertices; i++){	
+			free(result[i]);
+		}
+		printf("freeing result\n");
+		//free temp (1d arr)
+		free(temp);
+		printf("freeing temp\n");
+
+
+	} else { // send my_results to master node
+		printf("i'm node %d and i'm going to send my result to master\n", rank);
+			for(int i = 0; i < chunk_size; i++) {
+				MPI_Send(my_results[i],
+						 chunk_size*sizeof(long),
+						 MPI_LONG,
+						 0,
+						 0,
+						 MPI_COMM_WORLD
+						 );
+
+			}
+		printf("i'm node %d and i'm just sent my result to master\n", rank);
+	}
+
+
+	// printf("I'm process %d and the distance from vertex 1 to 2 is %d\n", 
+	// rank, 
+	// graph[0][1]);
+	// 
+	MPI_Barrier(MPI_COMM_WORLD);
+	finish_time = MPI_Wtime();
+
+	if (rank == 0) {
+		printf("elapsed time : %.lf ms\n", (finish_time-start_time)*1000000);
+	}
+	
+	
+	//free my_results (2d arr)
+	free(my_results);
+	printf("freed my_results\n");
+	//free graph (2d arr)
+	free(graph);
+	printf("freed graph\n");
+
+	MPI_Finalize();
+
+
+	return 0;
+}
\ No newline at end of file
diff --git a/src/paralel_openmp.c b/src/paralel_openmp.c
new file mode 100644
index 0000000000000000000000000000000000000000..cdfc6fd1fc8a8e793d0ac3ce113356125c56694a
--- /dev/null
+++ b/src/paralel_openmp.c
@@ -0,0 +1,77 @@
+#include <omp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "util.h"
+#include "dijkstra.h"
+#include "boolean.h"
+
+
+static double get_micros(void) {
+    struct timespec ts;
+    timespec_get(&ts, TIME_UTC);
+    return ((double)((long)ts.tv_sec * 1000000000L + ts.tv_nsec)/1000);
+}
+
+
+int main(int argc, char const *argv[])
+{
+	// int thread_count = strtol(argv[1], NULL, 10);
+	int num_vertices = atoi(argv[2]);
+	// int tid;
+
+	// time
+	double start_time, end_time, total_time;
+
+	// generate graph and result matrix
+	long **result = gen_temp(num_vertices, num_vertices);
+	long **graph = gen_graph(num_vertices);
+
+	long *temp = (long*) malloc(sizeof(long)*num_vertices);
+
+	// init time
+	total_time = 0;
+
+	#pragma omp barrier
+	
+	// start time
+	start_time = get_micros();
+
+	// share the work to all the threads
+	#pragma omp parallel for private(temp)
+	for (int i = 0; i < num_vertices; i++) {
+		// tid = omp_get_thread_num();
+		// printf("i: %d, by the way i'm thread %d\n", i, tid);
+		
+		// get the shortest path from each vertex
+		// get time execution
+
+
+		temp = dijkstra(graph, num_vertices, i);
+
+		// kalo barrier nya disini error
+		end_time = get_micros();
+
+		
+		// put it in result
+		// #pragma omp critical(result) 
+		// {
+		for (int j = 0; j < num_vertices; j++) {
+			result[i][j] = temp[j];
+		}
+		// }
+
+		total_time += end_time - start_time;
+	}
+		// #pragma omp barrier
+		// total_time += end_time - start_time;
+
+	char filename[20];
+	sprintf(filename, "./output_parallel_%d", num_vertices);
+	printf("about to write output file\n");
+	write_result(result, num_vertices, filename);
+	printf("done writing\n");
+	printf("processing time: %0.04lf us ...\n",total_time);
+
+	return 0;
+}
\ No newline at end of file
diff --git a/src/serial.c b/src/serial.c
new file mode 100644
index 0000000000000000000000000000000000000000..ec3acbbc4eb004484b8f960f2ba2e5447418e611
--- /dev/null
+++ b/src/serial.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include "dijkstra.h"
+#include "util.h"
+
+
+
+
+
+int main(int argc, char const *argv[])
+{
+	time_t start,end;
+	
+	if (argc > 1) {
+
+		int n = atoi(argv[1]);
+		printf("n: %d\n", n);
+
+		// start timer
+		start=clock(); 
+		// generate graph
+		long **graph = gen_graph(n);
+		
+		// result matrix
+		long **result = gen_temp(n, n);
+
+		for (int i = 0; i < n; i++) {
+        	long *dist = dijkstra(graph, n, i);
+        	result[i] = dist;
+		}
+		//end timer
+		end=clock();
+
+		//elapsed time
+		float t = (float)(end-start)/CLOCKS_PER_SEC;
+		printf("Elapsed time (in millisecond): %f", t*1000000);
+
+		char filename[20];
+		sprintf(filename, "./output_serial_%d", n);
+
+		write_result(result, n, filename);
+		
+		free(result);
+		free(graph);
+
+	} else {
+		printf("usage : serial [n]\n");
+	}
+
+	return 0;
+}
+
diff --git a/src/test b/src/test
new file mode 100755
index 0000000000000000000000000000000000000000..465cd19b9177f81e395688fb030a90603f419852
Binary files /dev/null and b/src/test differ
diff --git a/src/test.c b/src/test.c
new file mode 100644
index 0000000000000000000000000000000000000000..f5bda7e30a701fd0172c92445434e8108198a763
--- /dev/null
+++ b/src/test.c
@@ -0,0 +1,37 @@
+#include "dijkstra.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char const *argv[])
+{
+	long **result = gen_temp(10,5);
+	long **first = gen_temp(5,5);
+	long **second = gen_temp(5,5);
+
+	for (int i = 0; i < 5; i++) {
+		for (int j = 0; j < 5; j++) {
+			first[i][j] = 1 * i * j;
+			second[i][j] = 2 * i * j;
+		}
+	}
+
+	memcpy(result,
+			first,
+			5 * sizeof(int*)
+			);
+
+	memcpy(result+5,
+			second,
+			5 * sizeof(int*)
+			);
+
+	for (int i =0; i < 10; i++) {
+		for (int j =0; j < 5; j++) {
+			printf("%d ", result[i][j]);
+		}
+		printf("\n");
+	}
+
+	return 0;
+}
\ No newline at end of file
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000000000000000000000000000000000000..f3fece500221c440128976be80341a5e3655e11d
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,32 @@
+#include "util.h"
+
+
+/**
+ * write matrix of shortest distance from vertex i to j
+ * @param graph 2D array 
+ */
+void write_result(long **m, int n, char filename[]) {
+
+	FILE *outfile;
+
+	printf("here we go, writing file again\n");
+	outfile = fopen(filename,"w");
+	printf("file %s opened\n", filename);
+	if (outfile == NULL) {
+		printf("Error!\n");
+		exit(1);
+	}
+
+	printf("Writing output...\n");
+	for (int i = 0; i < n; i++) {
+		// printf("about to write row %d\n", i);
+		for (int j = 0; j < n; j++) {
+			fprintf(outfile, "%ld ", m[i][j]);
+		}
+		// printf("just write row %d\n", i);
+		fprintf(outfile, "\n");
+	}
+
+	printf("Done.\n");
+
+}
\ No newline at end of file
diff --git a/src/util.h b/src/util.h
new file mode 100644
index 0000000000000000000000000000000000000000..f58a1b1730ed5f8d0df8ce8a133f202baeba7e30
--- /dev/null
+++ b/src/util.h
@@ -0,0 +1,14 @@
+#ifndef UTIL_H
+#define UTIL_H
+#include <stdio.h>
+#include <stdlib.h>
+
+/**
+ * write matrix of shortest distance from vertex i to j
+ * @param m 2D array, m[i][j] = m[j][i] = shortest distance from vertex i to j
+ * @param n     dimension of matrix m
+ */
+void write_result(long **m, int n, char filename[]);
+
+
+#endif
\ No newline at end of file