def johnson(g: Graph): g.vertices["s"] = Vertex("s") g.neighbors["s"] = [] for vertex in g.vertices: g.edges.append(Edge("s", vertex, 0)) g.neighbors["s"] += [(vertex, 0)] bf = bellman_ford(g, "s") if not bf: print("Ujemny cykl") return distances_b_f, _ = bf for edge in g.edges: edge.weight = edge.weight + \ distances_b_f[edge.start] \ - distances_b_f[edge.end] s_edges = [edge for edge in g.edges if edge.start == "s"] for edge in s_edges: g.edges.remove(edge) g.vertices.pop("s") g.neighbors.pop("s") distances = {} path = {} for vertex in g.vertices: distances[vertex], path[vertex] = \ dijkstra(g, vertex) for v_1 in g.vertices: for v_2 in g.vertices: distances[v_1][v_2] += \ distances_b_f[v_2] - distances_b_f[v_1] for edge in g.edges: edge.weight = edge.weight + \ distances_b_f[edge.start] \ - distances_b_f[edge.end] return distances, path
def generate(vertices_number, edges_number): vertices = [] for i in range(vertices_number): name = "" first_letter = int(i / 26) second_letter = i % 26 if first_letter != 0: first_letter = chr(97 + first_letter - 1) name += first_letter second_letter = chr(97 + second_letter) name += second_letter vertices.append(Vertex(name)) edges = [] graph_edges = [] available_edges = [] for v_start in vertices: for v_end in vertices: if v_start == v_end: continue available_edges.append((v_start, v_end)) for i in range(edges_number): random_edge = random.choice(available_edges) edges.append(random_edge) available_edges.remove(random_edge) for edge in edges: start_vertex, end_vertex = edge weight = random.randint(0, 10) graph_edges.append(Edge(start_vertex.name, end_vertex.name, weight)) graph_edges.sort(key=operator.attrgetter('start', 'end')) graph = Graph(vertices={vertex.name: vertex for vertex in vertices}, edges=graph_edges) return graph
from described.bellman_ford import bellman_ford, \ print_bellman_ford from described.graph import Edge, Graph, Vertex G = Graph(vertices={ "a": Vertex("a"), "b": Vertex("b"), "c": Vertex("c"), "d": Vertex("d"), "e": Vertex("e") }, edges=[ Edge("a", "b", 4), Edge("a", "c", 5), Edge("b", "a", -3), Edge("b", "c", -4), Edge("c", "d", 7), Edge("d", "b", 9), Edge("d", "e", 10), Edge("e", "b", 8) ]) print_bellman_ford(G, "e", bellman_ford(G, "e"))
from described.graph import Edge, Graph, Vertex from described.johnson import johnson, print_johnson G = Graph(vertices={ "a": Vertex("a"), "b": Vertex("b"), "c": Vertex("c"), "d": Vertex("d"), "e": Vertex("e") }, edges=[ Edge("a", "b", -1), Edge("a", "d", 8), Edge("a", "e", 1), Edge("b", "c", -3), Edge("b", "e", -4), Edge("c", "a", 9), Edge("c", "e", 2), Edge("d", "c", -6), Edge("e", "d", 7) ]) print_johnson(G, johnson(G))
from described.floyd_warshall import floyd_warshall, \ print_floyd_warshall from described.graph import Edge, Graph, Vertex G = Graph(vertices={ "a": Vertex("a"), "b": Vertex("b"), "c": Vertex("c"), "d": Vertex("d"), "e": Vertex("e") }, edges=[ Edge("a", "c", -3), Edge("a", "d", 2), Edge("b", "a", -5), Edge("b", "c", 4), Edge("c", "d", 6), Edge("d", "e", 1), Edge("e", "b", 9), Edge("e", "c", -4) ]) print_floyd_warshall(G, floyd_warshall(G))
from described.dijkstra import dijkstra, print_dijkstra from described.graph import Edge, Graph, Vertex G = Graph(vertices={ "a": Vertex("a"), "b": Vertex("b"), "c": Vertex("c"), "d": Vertex("d"), "e": Vertex("e"), "f": Vertex("f") }, edges=[ Edge("a", "b", 7), Edge("a", "c", 9), Edge("a", "f", 14), Edge("b", "c", 10), Edge("b", "d", 15), Edge("c", "d", 11), Edge("c", "f", 2), Edge("d", "e", 6), Edge("e", "f", 9) ]) dijkstra(G, "a") print_dijkstra(G, "a")
from described.bellman_ford import bellman_ford, print_bellman_ford from described.graph import Edge, Graph, Vertex G = Graph(vertices={ "a": Vertex("a"), "b": Vertex("b"), "c": Vertex("c"), "d": Vertex("d"), "e": Vertex("e") }, edges=[ Edge("a", "c", 10), Edge("a", "b", 3), Edge("b", "a", 2), Edge("c", "d", -9), Edge("d", "e", 7), Edge("e", "a", 1), Edge("e", "c", -5) ]) print_bellman_ford(G, "a", bellman_ford(G, "a"))
def johnson(g: Graph): """ Funkcja algorytmu Johnsona :param g: Obiekt klasy Graph, graf na którym wykonujemy algorytm :type g: Graph :return: Najkrótsze ścieżki między wszystkimi wierzchołkami oraz listę poprzedników Zwracana jest krotka: (distances, path) zawierająca odległości między wszystkimi wierzchołkami oraz macierz poprzedników oprócz zwracania wyników, algorytm przypisuje wyniki do obiektów wierzchołków grafu (klasa Vertex) """ # sprawdzanie na wstępie czy graf zawiera ujemny cykl, nadmiarowe - usunięcie przyśpieszy w pewnym stopniu algorytm # przechodzimy przez wszystkie wierzchołki dlatego, że dla wierzchołka izolowanego lub takiego, który nie ma # krawędzi wychodzących algorytm bellmana_forda nie zwróci False, tylko dla każdego wierzchołka odległość będzie inf for vertex in g.vertices: # code może być wartością kodu błędu (-1 lub -2) lub też poprawnym wynikiem algorytmu code = bellman_ford(g, vertex) # -1 oznacza ujemny cykl wtedy wychodzimy z funkcji if code == -1: print("Ujemny cykl") return False # -2 oznacza że wierzchołek nie zawiera krawędzi wychodzących więc nie można stwierdzić czy występuje # ujemny cykl, więc przechodzimy do następnego elif code == -2: continue # jeśli nie nastąpił żaden błąd to graf nie zawiera ujemnych cykli - można przejść do algorytmu else: break # tworzymy pomocniczy wierzchołek "-s" oraz krawędzie z wierzchołka "-s" do każdego innego w grafie g.vertices["-s"] = Vertex("-s") g.neighbors["-s"] = [] for vertex in g.vertices: g.edges.append(Edge("-s", vertex, 0)) g.neighbors["-s"] += [(vertex, 0)] # po utworzeniu wierzchołka "-s" obliczamy odległości z wierzchołka "-s" do pozostałych wierzchołków # dodatkowo sprawdzamy czy graf nie zawiera ujemnych cykli, jeśli tak to wychodzimy z funkcji result = bellman_ford(g, "-s") # jeśli algorytm Bellmana-Forda zwróci False, również algorytm Johnsona zwraca False - ujemny cykl if not result: return False distances_b_f, _ = result # zmieniamy wagi dla każdej krawędzi uwzględniając odległości wyliczone przez algorytm Bellmana-Forda # przez co likwidujemy ujemne wagi i umożliwiamy użycie algorytmu Dijkstry for edge in g.edges: edge.weight = edge.weight + distances_b_f[edge.start] - distances_b_f[edge.end] # usuwamy wierzchołek "-s" oraz wszystkie krawędzie wyprowadzone z tego wierzchołka s_edges = [edge for edge in g.edges if edge.start == "-s"] for edge in s_edges: g.edges.remove(edge) g.vertices.pop("-s") g.neighbors.pop("-s") # wyliczamy algorytmem Dijkstry odległości i poprzedniki dla każdego wierzchołka distances = {} path = {} for vertex in g.vertices: distances[vertex], path[vertex] = dijkstra(g, vertex) # ponownie zmieniamy wagi dla każdej krawędzi oraz poprawiamy odległości uwzględniając poprzednio zmienione # ujemne wagi for v_1 in g.vertices: for v_2 in g.vertices: distances[v_1][v_2] += distances_b_f[v_2] - distances_b_f[v_1] for edge in g.edges: edge.weight = edge.weight + distances_b_f[edge.start] - distances_b_f[edge.end] # zwracamy krotkę zawierającą odległości oraz macierz poprzedników return distances, path