def ucs_dictionary_approach(graph, start, goal):
"""
Uniform-Cost Search using simple dictionary approach
Much easier to understand than priority queues!
Args:
graph: Dictionary where keys are nodes and values are lists of (neighbor, cost) tuples
start: Starting node
goal: Goal node
Returns:
(path, total_cost) or (None, float('inf')) if no path exists
"""
print(f"š Starting UCS Dictionary Approach: {start} ā {goal}")
print("=" * 50)
# Initialize: All nodes start with infinite cost except start node
unvisited = {node: float('inf') for node in graph.keys()}
unvisited[start] = 0
# Track visited nodes and parent pointers for path reconstruction
visited = set()
parent = {start: None}
print(f"š Initial unvisited dictionary: {dict(unvisited)}")
print(f"šÆ Looking for path to: {goal}")
print()
while unvisited:
# STEP 1: Find the unvisited node with minimum cost (simple linear search)
current = min(unvisited, key=unvisited.get)
current_cost = unvisited[current]
print(f"š Step: Finding minimum cost node from unvisited")
print(f"š Unvisited nodes: {dict(unvisited)}")
print(f"ā Selected: {current} with cost {current_cost}")
# If we reached an unreachable node (infinite cost), no path exists
if current_cost == float('inf'):
print(f"ā No path to {goal} exists (all remaining nodes unreachable)")
return None, float('inf')
# STEP 2: Remove current node from unvisited (mark as processed)
del unvisited[current]
visited.add(current)
print(f"ā
Moved {current} from unvisited to visited")
print(f"šļø Visited nodes: {visited}")
# STEP 3: Check if we reached the goal
if current == goal:
path = reconstruct_path(parent, start, goal)
print(f"šÆ Goal {goal} reached!")
print(f"š Optimal path: {' ā '.join(path)}")
print(f"š° Total cost: {current_cost}")
return path, current_cost
# STEP 4: Update costs for all neighbors
print(f"š Examining neighbors of {current}:")
neighbors = graph.get(current, [])
for neighbor, edge_cost in neighbors:
if neighbor not in visited: # Only check unvisited neighbors
new_cost = current_cost + edge_cost
old_cost = unvisited.get(neighbor, float('inf'))
print(f" šļø Neighbor: {neighbor}")
print(f" š Path cost via {current}: {current_cost} + {edge_cost} = {new_cost}")
print(f" š Current best cost for {neighbor}: {old_cost}")
# Update if we found a better path
if new_cost < old_cost:
unvisited[neighbor] = new_cost
parent[neighbor] = current
print(f" ⨠Updated! New best cost for {neighbor}: {new_cost}")
else:
print(f" ā« No improvement (kept {old_cost})")
else:
print(f" āļø {neighbor}: already visited, skipping")
print(f"š Updated unvisited dictionary: {dict(unvisited)}")
print("-" * 50)
# If we exit the loop without finding goal
print(f"ā Goal {goal} not reachable from {start}")
return None, float('inf')
def reconstruct_path(parent, start, goal):
"""Reconstruct path from parent pointers"""
path = []
current = goal
while current is not None:
path.append(current)
current = parent.get(current)
path.reverse()
return path if path[0] == start else []
# Example: Saudi Cities with real distances (km)
saudi_cities = {
'Riyadh': [('Qassim', 408), ('Jeddah', 849)],
'Qassim': [('Riyadh', 408), ('Medina', 320)],
'Medina': [('Qassim', 320), ('Jeddah', 420)],
'Jeddah': [('Riyadh', 849), ('Medina', 420), ('Makkah', 80)],
'Makkah': [('Jeddah', 80)]
}
if __name__ == "__main__":
print("š UCS DICTIONARY APPROACH: RIYADH TO MAKKAH")
print("=" * 60)
path, cost = ucs_dictionary_approach(saudi_cities, 'Riyadh', 'Makkah')
print(f"\nš FINAL SUMMARY:")
print(f"š Start: Riyadh")
print(f"šÆ Goal: Makkah")
if path:
print(f"š¤ļø Optimal Path: {' ā '.join(path)}")
print(f"š° Total Cost: {cost} km")
print(f"šļø Cities Visited: {len(path)}")
print(f"š Algorithm: Simple Dictionary UCS (Easy to understand!)")
else:
print(f"ā No path found")
print("\nš¬ ALGORITHM ANALYSIS:")
print("ā
Uses simple dictionary operations (no complex data structures)")
print("ā
Easy to debug and understand step-by-step")
print("ā
Same optimal results as priority queue version")
print("ⰠTime complexity: O(V²) for simple graphs")
print("š¾ Space complexity: O(V) for storing costs and visited nodes")