Download as pdf or txt
Download as pdf or txt
You are on page 1of 25

PROJECT 7

Shortest and Longest Paths

NAME: AIMAN MOHAMMED

莫海

ID:228801136

Professor: Bin Chen

Data Structures and Algorithms


Table of Contents
Chapter 1: Dijkstra's Algorithm Overview.................................................................................4
Chapter 2: Problem Understanding ............................................................................................5
Grids as Graphical Models:.....................................................................................................5
Chapter 3: Problem Solution ......................................................................................................8
Chapter 4: Implementation and Pseudo Code ..........................................................................10
Chapter 5: Testing and Results.................................................................................................13
Chapter 6: Project Experience ..................................................................................................17
CHAPTER 7: THE CODE .......................................................................................................22
Chapter 1: Dijkstra's Algorithm Overview

Introduction

Dijkstra's algorithm stands as a prominent solution for graph traversal, specifically addressing
the single source shortest path problem. In this implementation, we extend Dijkstra's
algorithm to not only calculate the shortest distances between vertices but also to track the
longest path within a grid. By utilizing a priority queue to manage vertices, the algorithm
efficiently explores the graph, updating distances when shorter paths are found. This
comprehensive approach allows us to uncover both the shortest and longest paths within the
grid

Grid-Based Graphs and Their Significance

Grid-based graphs, represented as two-dimensional arrays, offer a versatile representation for


various real-world scenarios. The extended Dijkstra's algorithm presented in the code
leverages these grids, where each cell corresponds to a vertex, and connections between
adjacent cells form the graph's edges. The algorithm navigates through the grid, efficiently
calculating shortest distances from the starting vertex to all others, and concurrently
identifying the longest path. The applications of this approach extend to optimizing
transportation routes, pinpointing critical paths, and evaluating overall grid connectivity.
Chapter 2: Problem Understanding

Comprehensive Contextualization of Grid-Based Graphs and Algorithm


Objectives

In our code implementation, grids are fundamental components represented as two-


dimensional arrays. These grids serve as powerful tools for modeling diverse real-world
scenarios, where each cell corresponds to a vertex and the interconnections between
adjacent cells define the underlying graph's edges. This section delves into the
contextualization of grid-based graphs within the extended Dijkstra's algorithm, highlighting
the significance of this approach in efficiently computing both shortest distances and longest
paths

Grids as Graphical Models:

1. Graph Representation
In our code, the grid is a graphical representation of a connected network. The structured
arrangement of vertices within the two-dimensional array mirrors the spatial relationships
between elements in various scenarios.

2. Vertex-Cell Mapping
Every cell in the grid uniquely represents a vertex. The association between vertex numbers
and grid cells establishes a direct correspondence, facilitating the translation of abstract graph
concepts into tangible grid structures.
3. Edge Definition
Connections between adjacent cells delineate the graph's edges. These edges define the
pathways and relationships between vertices, crucial for understanding the connectivity and
pathways within the represented scenario.

Extended Dijkstra's Algorithm in Grid Context:

1. Algorithmic Adaptation
Dijkstra's algorithm, a renowned graph traversal technique, is extended to accommodate grid-
based scenarios. The algorithm maintains a priority queue of vertices, prioritizing minimum
distances, and iteratively explores the grid, updating distances and tracking the longest path.

2. Efficiency in Computation
The adaptation of Dijkstra's algorithm to grid-based graphs enhances computational
efficiency. By leveraging the grid structure, the algorithm minimizes redundant calculations,
optimizing the determination of both shortest paths and the longest route.

Motivation and Objectives :

1. Holistic Grid Connectivity


The motivation behind extending Dijkstra's algorithm is rooted in the quest for a
comprehensive understanding of grid connectivity. Grids often represent intricate networks,
and uncovering the longest path contributes to a nuanced comprehension of the overall
structure.

2. Applications in Decision-Making
Identifying the longest path in a grid aligns with broader objectives related to urban planning,
transportation network analysis, and infrastructure optimization. The dual functionality of
computing shortest distances and longest paths equips users with valuable insights for
informed decision-making.
3. Optimization and Resource Allocation

The primary objective is to offer a reliable and efficient solution that not only calculates
shortest distances but also reveals the longest path within the grid. This dual capability
empowers users to optimize transportation routes, identify critical paths, and allocate
resources judiciously.

Grid-based graphs, as represented in our code, provide a versatile framework for modeling
real-world scenarios. The extended Dijkstra's algorithm, tailored to exploit the grid structure,
emerges as a powerful tool for simultaneously calculating shortest distances and identifying
the longest path. This comprehensive approach contributes to a myriad of applications,
ranging from urban planning to infrastructure optimization, enriching decision-making
..processes and resource allocation strategies
Chapter 3: Problem Solution
In the context of Dijkstra's algorithm implementation, the grid plays a pivotal role, serving as
the foundation for the graph representation. This section provides an extensive explanation
of the grid creation process, detailing how a two-dimensional array is generated with unique
vertex numbers assigned to each cell. The dimensions of the grid are determined by
predefined constants ROWS and COL

Grid Creation Process

The grid creation process is executed through the `create_grid` function within the
`DijkstraGrid` class. This function initializes the two-dimensional array, ensuring that each cell
corresponds to a unique vertex. The steps involved in this process are as follows:

1. Two-Dimensional Array Initialization

A blank two-dimensional array is created to store the vertices, with the dimensions specified
by the constants ROWS and COLS. The array is initially empty, and each element is initialized
to zero

python```
grid = [[0 for j in range(COLS)] for i in range(ROWS)]
```

2. Assigning Unique Vertex Numbers

The function then iterates over each cell in the array, assigning a unique vertex
number to it. The vertex numbers are determined based on the row and column
indices, ensuring a systematic assignment
python```
vertex = 0
:for i in range(ROWS)
:for j in range(COLS)
grid[i][j] = vertex
vertex += 1
```

3. Finalizing the Grid

Once all cells have been assigned unique vertex numbers, the grid creation process is
complete. The resulting two-dimensional array now serves as the graphical
representation of the vertices within the algorithm

The grid creation process is a crucial step in preparing the data structure for Dijkstra's
algorithm. By systematically assigning unique vertex numbers to each cell, the
algorithm gains the necessary foundation to explore the connectivity of the graph.
This grid, represented as a two-dimensional array, facilitates efficient traversal and
computation of shortest distances and the longest path. The subsequent application
of Dijkstra's algorithm on this grid ensures a comprehensive analysis of the graph's
..topology
Chapter 4: Implementation and Pseudo Code

Comprehensive Explanation of Dijkstra's Algorithm Implementation

This document provides a detailed breakdown of the implementation of Dijkstra's


algorithm in the given Python code. The algorithm is designed to find the shortest
paths from a specified starting vertex to all other vertices in a grid-based graph. We
will explore the data structures and algorithms used, the process of creating the grid,
and the step-by-step execution of Dijkstra's algorithm

1. Data Structures and Algorithms Used

Two-dimensional Array
The grid is represented as a two-dimensional array. This array stores the vertices and
their corresponding indexes in the grid. Each cell in the array corresponds to a unique
vertex, forming the basis for the graph representation

Priority Queue
A priority queue is utilized to efficiently retrieve the vertex with the minimum distance
during each iteration of Dijkstra's algorithm. This priority queue is implemented using
a binary heap, ensuring that the vertex with the smallest distance is always at the
front of the queue. The PriorityQueue is essential for optimizing the selection of
vertices during the traversal
2. Creating the Grid

The `create_grid` function initializes the grid based on the specified number of rows
and columns. It iterates over each position in the grid, assigns a unique vertex value to
it, and increments the vertex value for the next position. This ensures that each cell in
the grid corresponds to a unique vertex, creating a structured representation of the
graph

3. Dijkstra's Algorithm in Detail

Initialization
The `calculate_distances` function initializes an array called `distances` with
`Integer.MAX_VALUE` for all vertices except the start vertex, which is set to 0. This
array stores the shortest distances from the start vertex to each vertex in the grid
It initializes a variable called `longestPath` to keep track of the longest path found
during the algorithm
A priority queue called `pq` is created to store vertices along with their distances. The
start vertex is added to the priority queue with a distance of 0

Iterative Process
The algorithm continues until the priority queue becomes empty
In each iteration, the vertex with the minimum distance is extracted from the priority
queue
The algorithm checks the neighboring vertices (right and below) of the current vertex
and calculates the distance to reach those vertices from the start vertex
If the newly calculated distance is smaller than the current distance stored in the
`distances` array, the distance is updated, and the vertex is added to the priority
.queue with the new distance
The algorithm also keeps track of the longest path found so far by updating the
`longestPath` variable if a longer path is discovered
Result

Once all vertices have been processed, the function returns an instance of the `Result`
class, which contains the `distances` array and the `longestPath` value

Priority Queue and Vertex Distances

The `pq` priority queue stores objects of the `VertexDistance` class, representing a
vertex along with its distance from the start vertex.
The `VertexDistance` class implements the `Comparable` interface, allowing the
.priority queue to prioritize vertices based on their distances
The `distance` variable in the `VertexDistance` class represents the distance of a vertex
.from the start vertex
During each iteration of the algorithm, the vertex with the minimum distance is
extracted from the priority queue (`pq.poll()`), and its neighboring vertices are
.processed to update their distances if necessary

Displaying the Grid and Schedule

The `display_grid` function prints the grid to the console, displaying the vertex values
.in a formatted manner
The `display_schedule` function prints a schedule that shows the starting vertex, the
directed vertices, and their corresponding distances. It iterates over the grid and
prints the schedule for each vertex. Additionally, it displays the longest path found
during the algorithm

Pseudocode

The provided pseudocode in the `main` function is a structured representation of the


entire process, from grid initialization to displaying the results. It acts as a blueprint for
the execution of the algorithm
Overall Execution

The `main` function initializes the grid, specifies the starting vertex, and calls the
`calculate_distances` function to obtain the distances and the longest path. It then
displays the grid, the distances, and the longest path using the `display_grid` and
.`display_schedule` functions, respectively

In conclusion, the code efficiently creates a grid, applies Dijkstra's algorithm to


calculate shortest distances and the longest path, and displays the results in
a structured manner. The use of priority queues enhances the algorithm's efficiency,
..making it suitable for various graph scenarios

Chapter 5: Testing and Results


The purpose of this testing is to evaluate the efficiency and correctness of the
Dijkstra's algorithm implementation on a grid-based graph. The code provided aims to
find both the shortest distances from a starting vertex to all other vertices and the
longest path within the given grid. We will conduct several tests to explore the
versatility of the algorithms

Test 1: Basic Grid


Input:
A small grid (4x5) is used

Expected Output:
The distances from the starting vertex to all other vertices
A schedule showing the starting vertex, directed vertices, and corresponding
distances.
The longest path within the grid.

Test 2: Larger Grid


Input:
A larger grid (6x6) with more vertices

Expected Output:
Similar to Test 1, but for the larger grid.

Test 3: Random Grid


Input:
A random grid (5x4) is used.

Expected Output:
Similar to Test 1, but for the random grid.
Test 4: Edge Case - Single Vertex

Input:
A grid with only one vertex

Expected Output:
The distances should show that the only vertex has a distance of 0
The longest path is 0

Test 5: Edge Case - No Rows or Columns


:Input
A grid with 0 rows and 0 columns

Expected Output:
The program should gracefully handle this case, possibly with an appropriate message.
Test Execution
Test 1
python
Copy code
DijkstraGrid.ROWS = 4
DijkstraGrid.COLS = 5
)(DijkstraGrid.main
Test 2
python
Copy code
DijkstraGrid.ROWS = 6
DijkstraGrid.COLS = 6
)(DijkstraGrid.main
Test 3
python
Copy code
DijkstraGrid.ROWS = 5
DijkstraGrid.COLS = 4
)(DijkstraGrid.main
Test 4
python
Copy code
DijkstraGrid.ROWS = 1
DijkstraGrid.COLS = 1
)(DijkstraGrid.main
Test 5
python
Copy code
DijkstraGrid.ROWS = 0
DijkstraGrid.COLS = 0

)(DijkstraGrid.main
Results Analysis
Observations
Review the distances from the starting vertex to other vertices.
Analyze the schedule to ensure correctness in directed vertices and distances.
Verify that the longest path is accurately identified.
The algorithm is expected to perform consistently across various grid sizes and
configurations.
The schedule should provide insights into how the algorithm navigates the grid.

Summary

The testing and analysis will provide a comprehensive understanding of the algorithm's
behavior in different scenarios, ensuring its reliability and adaptability. It will also highlight any
potential edge cases that need to be addressed for a robust implementation.
Chapter 6: Project Experience

Embarking on the journey of implementing Dijkstra's algorithm for grid-based graphs


has been an enlightening project experience. This section explores key takeaways,
shedding light on algorithmic understanding, visualization skills, practical priority
queue application, longest path tracking, and the hands-on learning garnered
throughout the project.
Algorithm Understanding

1. Dijkstra's Algorithm Adaptation


The core of the project lies in the adaptation of Dijkstra's algorithm to suit grid-based
graphs. Understanding how the algorithm traverses the grid, prioritizes vertices, and
efficiently computes both shortest distances and the longest path has enriched
comprehension.

2. Grid Specifics
Navigating the intricacies of translating abstract graph concepts into grid structures
deepens the understanding of graph representation. Each cell as a vertex and the
connections between cells as edges adds a layer of complexity and practicality to the
algorithm.

- Visualization Skills

1. Grid Visualization
The inclusion of functions to visualize grid structures is pivotal. The ability to witness
the grid dynamically fosters a deeper understanding of graph connectivity. Visual cues
aid in grasping the relationships between vertices and comprehending the algorithm's
execution.
2. Iterative Exploration
Observing the step-by-step exploration of the grid during the algorithm's execution
enhances visualization skills. The iterative nature of Dijkstra's algorithm becomes
tangible, providing a visual narrative of how distances are updated and the longest
path is tracked.

- Practical Priority Queue Application

1. Priority Queue Dynamics


The code's utilization of a priority queue for managing vertices showcases the practical
application of data structures. Understanding how the priority queue ensures efficient
retrieval of vertices with minimal distances elucidates the synergy between algorithmic
concepts and real-world implementations.

2. Hands-On Priority Queue Manipulation


Interacting with the code provides hands-on experience in manipulating the priority queue during each
iteration. Insights into how vertices are added, prioritized, and dequeued contribute to a practical
understanding of priority queue dynamics.
- Longest Path Tracking

1. Algorithmic Flexibility
The project extends the conventional Dijkstra's algorithm by incorporating longest path
tracking. This showcases the algorithm's flexibility, highlighting its adaptability to different
analytical needs beyond the standard shortest path determination.

2. Comprehensive Analysis
The ability to track the longest path adds depth to the algorithm's analytical capabilities. It
opens avenues for comprehensive graph analysis, especially in scenarios where understanding
the connectivity beyond the immediate shortest paths is crucial.
Hands-On Learning

1. Real-World Applications

Interacting with the code in practical scenarios bridges the gap between theoretical
knowledge and real-world applications. The project's hands-on nature allows for a holistic
understanding of algorithmic processes and their relevance in solving complex problems.

2. Iterative Problem Solving

Engaging with the code fosters iterative problem-solving skills. Tackling challenges
related to grid-based graphs, algorithmic adaptations, and visualization instills a

problem-solving mindset crucial for future projects and applications.

The project experience goes beyond mere code implementation, offering a journey of
discovery and learning. From algorithmic intricacies to practical visualization and
hands-on priority queue manipulation, the project provides a comprehensive
exploration of Dijkstra's algorithm in the context of grid-based graphs. This newfound
understanding lays a solid foundation for future algorithmic endeavors and real-world
problem-solving
CHAPTER 7: THE CODE

import heapq

:class DijkstraGrid
ROWS = 4
COLS = 5

staticmethod@
:)(def main
grid = DijkstraGrid.create_grid(DijkstraGrid.ROWS, DijkstraGrid.COLS)
start_vertex = 0
result = DijkstraGrid.calculate_distances(grid, start_vertex)

print("NOTE: THE WEIGHT OF EACH EDGE IS 1")


print("Distance from the starting vertex to each vertex:")
print("Grid:")
DijkstraGrid.display_grid(grid)
print("Schedule:")
DijkstraGrid.display_schedule(grid, result['distances'], result['longestPath'])

staticmethod@
:def create_grid(rows, cols)
grid = [[i * cols + j for j in range(cols)] for i in range(rows)]
return grid

staticmethod@
:def calculate_distances(grid, start_vertex)
total_vertices = len(grid) * len(grid[0])
distances = [float('inf')] * total_vertices
distances[start_vertex] = 0
longest_path = 0
pq = [(0, start_vertex)]

:while pq
distance, vertex = heapq.heappop(pq)
:if distance > longest_path
longest_path = distance

row, col = divmod(vertex, DijkstraGrid.COLS)

Check the vertex to the right #


if col + 1 < DijkstraGrid.COLS and distance + 1 < distances[grid[row][col +
:1]]
distances[grid[row][col + 1]] = distance + 1
heapq.heappush(pq, (distance + 1, grid[row][col + 1]))

Check the vertex below #


if row + 1 < DijkstraGrid.ROWS and distance + 1 < distances[grid[row +
:1][col]]
distances[grid[row + 1][col]] = distance + 1
heapq.heappush(pq, (distance + 1, grid[row + 1][col]))

return {'distances': distances, 'longestPath': longest_path}

staticmethod@
:def display_grid(grid)
:for row in grid
:for vertex in row
print(f"{vertex:<4}", end="")
)(print
)(print

staticmethod@
:def display_schedule(grid, distances, longest_path)
)"+--------------+--------------+--------------+"(print
print("| Starting Vtx | Directed Vtx | Distance |")
)"+--------------+--------------+--------------+"(print

:for i in range(len(grid))
:for j in range(len(grid[0]))
start_vertex = 0
directed_vertex = 0
distance = 0

:if grid[i][j] == start_vertex


print(f"| {start_vertex:<13}| {directed_vertex:<13}| {distance:<13}|")
:if j + 1 < DijkstraGrid.COLS
directed_vertex = grid[i][j + 1]
distance = distances[directed_vertex]
print(f"| {start_vertex:<13}| {directed_vertex:<13}| {distance:<13}|")
:if i + 1 < DijkstraGrid.ROWS
directed_vertex = grid[i + 1][j]
distance = distances[directed_vertex]
print(f"| {start_vertex:<13}| {directed_vertex:<13}| {distance:<13}|")

)"+--------------+--------------+--------------+"(print
print("Longest path:", longest_path)

:class VertexDistance
:def __init__(self, vertex, distance)
self.vertex = vertex
self.distance = distance

:def __lt__(self, other)


return self.distance < other.distance

:class Result
:def __init__(self, distances, longest_path)
self.distances = distances
self.longest_path = longest_path

Run the main method #


)(DijkstraGrid.main

You might also like