A Star Algorithm
A Star Algorithm
finding the shortest path from a start node to a goal node in a weighted graph. Unlike Dijkstra's
algorithm, A* uses both the current cost and a heuristic to estimate the remaining cost to the
goal. This heuristic guides the search and typically leads to faster solutions when a good heuristic
is used.
In the context of network flow problems, A* is not typically used directly, as flow problems
focus on maximizing or minimizing flow through the network rather than finding the shortest
path. However, we can apply A* in pathfinding problems that might be relevant to finding an
optimal path with costs (e.g., in routing or finding the least-cost path in a weighted graph).
Here is a step-by-step numerical example of the A* algorithm, which is used to find the shortest
path in a weighted graph while considering a heuristic (estimated cost) to guide the search.
Example 1
Consider the following graph:
From To Weight
A B 1
A C 4
B C 2
B D 5
C D 1
C E 3
D E 2
A 7
B 6
C 2
D 1
1
Node E (to Goal E)
E 0
Goal
Find the shortest path from A to E using the A* algorithm.
Definitions in A*
1. g(n): Actual cost from the start node to the current node n.
2. h(n): Heuristic cost (estimated cost from node n to the goal).
3. f(n): Total estimated cost f(n) = g(n)+h(n).
Step-by-Step Execution
Initialization
1. Start at node A:
o g(A) = 0, h(A) = 7, f(A) = g(A)+h(A) = 7.
o C(f = 6)
2
Step 2: Explore Neighbors of C
From C:
o g(D) = g(C)+weight(C→D) = 4+1 = 5, h(D) = 1, f(D) = 5+1 = 6.
o D(f = 6)
o E(f = 7)
o E(f = 7)
Final Path
Trace back the path using the predecessors:
Path: A→C→D→E
Cost: g(E) = 7
3
Summary of A* Algorithm for the Example
1. Starts at the source node A.
2. Explores nodes based on the total estimated cost f(n) = g(n)+h(n).
3. Ensures the shortest path is found by balancing actual costs (g) with heuristic estimates
(h).
4. The shortest path from A to E is A→C→D→E with a total cost of 7.
Python Code
import heapq
class Node:
def __init__(self, name, g=0, h=0, parent=None):
self.name = name
self.g = g # Cost from start node
self.h = h # Heuristic cost to goal
self.f = g + h # Total cost
self.parent = parent
while open_list:
current_node = heapq.heappop(open_list)
print(f"Expanding node: {current_node.name}, g: {current_node.g}, h:
{current_node.h}, f: {current_node.f}")
if current_node.name == goal:
path = []
cost = current_node.g # Capture total cost
while current_node:
path.append(current_node.name)
current_node = current_node.parent
print("Goal reached!")
return path[::-1], cost
closed_set.add(current_node.name)
4
if neighbor in closed_set:
continue
graph = {
'A': {'B': 1, 'C': 4},
'B': {'C': 2, 'D': 5},
'C': {'D': 1, 'E': 3},
'D': {'E': 2},
'E': {}
}
start = 'A'
goal = 'E'
5
o Outputs the shortest path and total cost.
Python Output
Expanding node: A, g: 0, h: 7, f: 7
Considering neighbor B, g: 1, h: 6, f: 7
Considering neighbor C, g: 4, h: 2, f: 6
Expanding node: C, g: 4, h: 2, f: 6
Considering neighbor D, g: 5, h: 1, f: 6
Considering neighbor E, g: 7, h: 0, f: 7
Expanding node: D, g: 5, h: 1, f: 6
Considering neighbor E, g: 7, h: 0, f: 7
Expanding node: E, g: 7, h: 0, f: 7
Goal reached!
Shortest path: ['A', 'C', 'D', 'E']
Total cost: 7Shortest path: ['A', 'C', 'D', 'E'] Total cost: 7
Example 2
We are given a graph where each edge has a weight (cost), and we need to find the shortest path
from a start node to a goal node using the A* Algorithm.
Graph Representation
Vertices: {A, B, C, D, E}
A → B: 2
A → C: 4
B → C: 1
B → D: 7
C → D: 3
C → E: 5
D → E: 1
We also have a heuristic estimate of the distance from each vertex to the goal (E):
A* Algorithm Steps:
1. Initialization:
o For each node, maintain the following:
g(n) (the cost from the start node to node n),
h(n) (the heuristic estimate from node n to the goal node),
6
f(n) = g(n) + h(n) (the estimated total cost from the start node to the
goal node via n).
o Initialize g(start) = 0 and f(start) = h(start).
2. Explore the nodes:
o Select the node with the smallest f(n) value, and explore its neighbors.
o For each neighbor, calculate g(neighbor) = g(current) + edge_cost.
o Update the f(neighbor) value and add the neighbor to the priority queue.
3. Repeat until the goal node is reached or all nodes are explored.
# A* algorithm implementation
def a_star(graph, heuristics, start, goal):
# Priority queue for exploring the nodes
open_list = []
heapq.heappush(open_list, (heuristics[start], start)) # (f(n), node)
while open_list:
# Get the node with the lowest f(n)
current_f, current_node = heapq.heappop(open_list)
7
path.append(current_node)
current_node = came_from[current_node]
path.append(start)
path.reverse()
return g_values[goal], path
# Explore neighbors
for neighbor, weight in graph[current_node]:
tentative_g = g_values[current_node] + weight
1. Graph Representation: The graph is represented as an adjacency list where each node
has a list of tuples. Each tuple contains a neighboring node and the cost to reach that
neighbor.
2. Heuristic Values: The heuristic function estimates the cost to the goal node E. These
values are given for each node in the graph.
3. Priority Queue: A priority queue (min-heap) is used to always expand the node with the
smallest f(n) value (the estimated total cost). The queue stores tuples of (f(n), node).
4. g(n) and f(n) Values:
o g(n) represents the known cost from the start node to node n.
o f(n) = g(n) + h(n) is the estimated cost from the start node to the goal node
via n.
5. Reconstruct Path: Once the goal node is reached, the algorithm reconstructs the path by
backtracking from the goal node using the came_from dictionary, which tracks the parent
node for each node.
Example Output:
mathematica
Copy code
Cost to reach E from A: 10
Path: A -> C -> D -> E
8
Step-by-Step Execution:
1. Start at A:
o g(A) = 0, h(A) = 6, f(A) = g(A) + h(A) = 6
o Add A to the priority queue with f(A) = 6.
2. Pop A (with f(A) = 6), explore its neighbors:
o A → B: g(B) = 0 + 2 = 2, f(B) = g(B) + h(B) = 2 + 4 = 6.
o A → C: g(C) = 0 + 4 = 4, f(C) = g(C) + h(C) = 4 + 2 = 6.
3. Pop B (with f(B) = 6), explore its neighbors:
o B → C: No update as the current cost to C is lower (f(C) = 6).
o B → D: g(D) = 2 + 7 = 9, f(D) = g(D) + h(D) = 9 + 1 = 10.
4. Pop C (with f(C) = 6), explore its neighbors:
o C → D: g(D) = 4 + 3 = 7, f(D) = g(D) + h(D) = 7 + 1 = 8 (update D).
o C → E: g(E) = 4 + 5 = 9, f(E) = g(E) + h(E) = 9 + 0 = 9 (update E).
5. Continue until the goal E is reached, and backtrack to get the path.
Conclusion:
The A* algorithm is an efficient and powerful search algorithm, especially when you have a
good heuristic function. In this example, we found the shortest path from A to E, considering
both the cost of the edges and the heuristic estimates of the remaining distance.