|
1 |
| -def print_dist(dist, v): |
2 |
| - print("\nVertex Distance") |
3 |
| - for i in range(v): |
4 |
| - if dist[i] != float("inf"): |
5 |
| - print(i, "\t", int(dist[i]), end="\t") |
6 |
| - else: |
7 |
| - print(i, "\t", "INF", end="\t") |
8 |
| - print() |
| 1 | +from typing import List |
9 | 2 |
|
| 3 | +def print_distances(distances: List[float]) -> None: |
| 4 | + print("\nVertex Distance") |
| 5 | + for vertex, distance in enumerate(distances): |
| 6 | + print(f"{vertex}\t{int(distance) if distance != float('inf') else 'INF'}") |
10 | 7 |
|
11 |
| -def min_dist(mdist, vset, v): |
12 |
| - min_val = float("inf") |
13 |
| - min_ind = -1 |
14 |
| - for i in range(v): |
15 |
| - if (not vset[i]) and mdist[i] < min_val: |
16 |
| - min_ind = i |
17 |
| - min_val = mdist[i] |
18 |
| - return min_ind |
| 8 | +def find_min_distance(distances: List[float], visited: List[bool]) -> int: |
| 9 | + min_distance = float("inf") |
| 10 | + min_index = -1 |
| 11 | + |
| 12 | + for i in range(len(distances)): |
| 13 | + if not visited[i] and distances[i] < min_distance: |
| 14 | + min_distance = distances[i] |
| 15 | + min_index = i |
| 16 | + |
| 17 | + return min_index |
19 | 18 |
|
| 19 | +def dijkstra(graph: List[List[float]], num_vertices: int, source: int) -> List[float]: |
| 20 | + distances = [float("inf")] * num_vertices |
| 21 | + visited = [False] * num_vertices |
| 22 | + distances[source] = 0 |
20 | 23 |
|
21 |
| -def dijkstra(graph, v, src): |
22 |
| - mdist = [float("inf") for _ in range(v)] |
23 |
| - vset = [False for _ in range(v)] |
24 |
| - mdist[src] = 0.0 |
| 24 | + for _ in range(num_vertices - 1): |
| 25 | + u = find_min_distance(distances, visited) |
| 26 | + visited[u] = True |
25 | 27 |
|
26 |
| - for _ in range(v - 1): |
27 |
| - u = min_dist(mdist, vset, v) |
28 |
| - vset[u] = True |
| 28 | + for v in range(num_vertices): |
| 29 | + if (not visited[v] and graph[u][v] != float("inf") |
| 30 | + and distances[u] + graph[u][v] < distances[v]): |
| 31 | + distances[v] = distances[u] + graph[u][v] |
29 | 32 |
|
30 |
| - for i in range(v): |
31 |
| - if ( |
32 |
| - (not vset[i]) |
33 |
| - and graph[u][i] != float("inf") |
34 |
| - and mdist[u] + graph[u][i] < mdist[i] |
35 |
| - ): |
36 |
| - mdist[i] = mdist[u] + graph[u][i] |
| 33 | + return distances |
37 | 34 |
|
38 |
| - print_dist(mdist, i) |
| 35 | +def is_connected(graph: List[List[float]], num_vertices: int) -> bool: |
| 36 | + visited = [False] * num_vertices |
| 37 | + stack = [0] # Start DFS from the first vertex |
| 38 | + visited[0] = True |
| 39 | + |
| 40 | + while stack: |
| 41 | + node = stack.pop() |
| 42 | + for neighbor in range(num_vertices): |
| 43 | + if graph[node][neighbor] != float("inf") and not visited[neighbor]: |
| 44 | + visited[neighbor] = True |
| 45 | + stack.append(neighbor) |
39 | 46 |
|
| 47 | + return all(visited) |
40 | 48 |
|
41 |
| -if __name__ == "__main__": |
| 49 | +def main() -> None: |
42 | 50 | V = int(input("Enter number of vertices: ").strip())
|
43 |
| - E = int(input("Enter number of edges: ").strip()) |
44 |
| - |
45 |
| - graph = [[float("inf") for i in range(V)] for j in range(V)] |
46 |
| - |
| 51 | + if V <= 0: |
| 52 | + print("Error: The number of vertices must be greater than 0.") |
| 53 | + return |
| 54 | + |
| 55 | + E = int(input("Enter number of edges (must be >= V-1): ").strip()) |
| 56 | + if E < V - 1: |
| 57 | + print(f"Error: The number of edges must be at least {V - 1} for a connected graph.") |
| 58 | + return |
| 59 | + |
| 60 | + graph = [[float("inf")] * V for _ in range(V)] |
| 61 | + |
47 | 62 | for i in range(V):
|
48 | 63 | graph[i][i] = 0.0
|
49 | 64 |
|
50 | 65 | for i in range(E):
|
51 |
| - print("\nEdge ", i + 1) |
52 |
| - src = int(input("Enter source:").strip()) |
53 |
| - dst = int(input("Enter destination:").strip()) |
54 |
| - weight = float(input("Enter weight:").strip()) |
| 66 | + print(f"\nEdge {i + 1}") |
| 67 | + src = int(input(f"Enter source (0 to {V - 1}): ").strip()) |
| 68 | + dst = int(input(f"Enter destination (0 to {V - 1}): ").strip()) |
| 69 | + |
| 70 | + if src < 0 or src >= V or dst < 0 or dst >= V: |
| 71 | + print("Error: Source and destination must be valid vertex indices.") |
| 72 | + return |
| 73 | + |
| 74 | + weight = float(input("Enter weight (non-negative): ").strip()) |
| 75 | + if weight < 0: |
| 76 | + print("Error: Weight must be non-negative.") |
| 77 | + return |
| 78 | + |
| 79 | + if src == dst: |
| 80 | + print("Warning: Self-loop detected; it will be allowed but consider its implications.") |
| 81 | + |
| 82 | + # Handle duplicate edges: (optionally overwrite or warn) |
| 83 | + if graph[src][dst] != float("inf"): |
| 84 | + print("Warning: Duplicate edge detected; the weight will be updated.") |
| 85 | + |
55 | 86 | graph[src][dst] = weight
|
56 | 87 |
|
57 |
| - gsrc = int(input("\nEnter shortest path source:").strip()) |
58 |
| - dijkstra(graph, V, gsrc) |
| 88 | + if not is_connected(graph, V): |
| 89 | + print("Warning: The graph is not connected. Dijkstra's algorithm may not yield valid results for all vertices.") |
| 90 | + |
| 91 | + gsrc = int(input(f"\nEnter shortest path source (0 to {V - 1}): ").strip()) |
| 92 | + if gsrc < 0 or gsrc >= V: |
| 93 | + print("Error: Source must be a valid vertex index.") |
| 94 | + return |
| 95 | + |
| 96 | + distances = dijkstra(graph, V, gsrc) |
| 97 | + print_distances(distances) |
| 98 | + |
| 99 | +if __name__ == "__main__": |
| 100 | + main() |
0 commit comments