def minimum_spanning_tree(adjacency_list): """ Get minimum spanning tree for graph represented as adjacency list """ remain_vertices = adjacency_list.copy() edges_by_vertex = {} mst = UndirectedGraph() for vertex in remain_vertices.keys(): edges_by_vertex[vertex] = None while remain_vertices: (vertex, adjacent_edges) = __extract_next_vertex_with_edges( remain_vertices, edges_by_vertex) if edges_by_vertex[vertex]: mst.add_edge(edges_by_vertex[vertex].start, edges_by_vertex[vertex].end, edges_by_vertex[vertex].weight) for edge in adjacent_edges: adjacent_vertex = edge.end is_not_visited = adjacent_vertex in remain_vertices is_lighter = edge.weight < __get_weight_or_inf( edges_by_vertex[adjacent_vertex]) if is_not_visited and is_lighter: edges_by_vertex[adjacent_vertex] = edge return mst
def test_returns_true_for_graph_with_cycle(self): g = UndirectedGraph() g.add_edge(1, 2, 1) g.add_edge(4, 1, 1) g.add_edge(2, 3, 1) g.add_edge(3, 1, 1) self.assertFalse(is_bipartite(g))
def test_can_add_multiple_edges_between_two_vertices(self): graph = UndirectedGraph() graph.add_edge(0, 1, 1) graph.add_edge(0, 1, 2) adjacency_list = graph.get_adjacency_list() self.assertEqual(2, len(adjacency_list)) self.assertEqual(2, len(adjacency_list[0])) self.assertListEqual([0, 0], sorted(map(lambda e: e.start, adjacency_list[0]))) self.assertListEqual([1, 1], sorted(map(lambda e: e.end, adjacency_list[0]))) self.assertListEqual([1, 2], sorted(map(lambda e: e.weight, adjacency_list[0]))) self.assertEqual(2, len(adjacency_list[1])) self.assertListEqual([1, 1], sorted(map(lambda e: e.start, adjacency_list[1]))) self.assertListEqual([0, 0], sorted(map(lambda e: e.end, adjacency_list[1]))) self.assertListEqual([1, 2], sorted(map(lambda e: e.weight, adjacency_list[1]))) edges = graph.get_edges() self.assertEqual(4, len(edges)) self.assertListEqual([0, 0, 1, 1], sorted(map(lambda e: e.start, edges))) self.assertListEqual([0, 0, 1, 1], sorted(map(lambda e: e.end, edges))) self.assertListEqual([1, 1, 2, 2], sorted(map(lambda e: e.weight, edges)))
def test_returns_minimum_edge_when_has_two_edges_with_different_weight( self): graph = UndirectedGraph() graph.add_edge(0, 1, 1) graph.add_edge(0, 1, 2) mst = minimum_spanning_tree(graph.get_adjacency_list()) self.__compare_vertices([0, 1], mst.get_adjacency_list()) self.__compare_edges([Edge(0, 1, 1), Edge(1, 0, 1)], mst.get_edges())
def test_returns_two_edges_for_two_edges_starting_in_same_vertex(self): graph = UndirectedGraph() graph.add_edge(0, 1, 1) graph.add_edge(0, 2, 2) mst = minimum_spanning_tree(graph.get_adjacency_list()) self.__compare_vertices([0, 1, 2], mst.get_adjacency_list()) self.__compare_edges( [Edge(0, 1, 1), Edge(1, 0, 1), Edge(0, 2, 2), Edge(2, 0, 2)], mst.get_edges())
def fixtured_graph() -> UndirectedGraph: graph = UndirectedGraph() graph.add_edge("A", "B", weight=2) graph.add_edge("A", "C", weight=4) graph.add_edge("B", "C", weight=1) graph.add_edge("C", "D", weight=3) graph.add_edge("B", "D", weight=5) graph.add_edge("D", "E", weight=6) graph.add_edge("D", "F", weight=8) return graph
def count_possible_astronaut_pairs(total_astronauts, astronauts_connections): """ Get number of possible astronaut pairs where both of them are from different countries """ graph = UndirectedGraph() for astronaut in range(0, total_astronauts): graph.add_vertex(astronaut) for connection in astronauts_connections: graph.add_edge(connection[0], connection[1], 0) country_by_astronaut = vertices_to_components(graph) count_by_country = {} for astronaut, country in country_by_astronaut.items(): count_by_country[country] = count_by_country.get(country, 0) + 1 total = 0 pairs = 0 for country, count in count_by_country.items(): pairs += total * count total += count return pairs
def count_number_of_road_forks(field): """ Returns number of times you are able to move in more than one direction by a given forest :param field: Array of strings that represent forest :return: number of road forks """ graph = UndirectedGraph() start = None end = None height = len(field) width = len(field[0]) for i, row in enumerate(field): for j, symbol in enumerate(row): if symbol == 'X': continue index = __linear_index(i, j, width) if symbol == 'M': start = index if symbol == '*': end = index if __can_go_to(i - 1, j, height, width): if field[i - 1][j] != 'X': neighbor_index = __linear_index(i - 1, j, width) graph.add_edge(neighbor_index, index, 1) if __can_go_to(i, j - 1, height, width): if field[i][j - 1] != 'X': neighbor_index = __linear_index(i, j - 1, width) graph.add_edge(neighbor_index, index, 1) path = dijkstra_path(graph, start, end) fork_count = 1 if len(graph.get_edges(start)) > 1 else 0 for vertex in path[1:-1]: if len(graph.get_edges(vertex)) - 1 > 1: fork_count += 1 return fork_count
def test_adding_single_edge_produces_two_directed_edges(self): graph = UndirectedGraph() graph.add_edge(0, 1, 1) adjacency_list = graph.get_adjacency_list() self.assertEqual(2, len(adjacency_list)) self.assertEqual(1, len(adjacency_list[0])) self.assertEqual(0, adjacency_list[0][0].start) self.assertEqual(1, adjacency_list[0][0].end) self.assertEqual(1, adjacency_list[0][0].weight) self.assertEqual(1, len(adjacency_list[1])) self.assertEqual(1, adjacency_list[1][0].start) self.assertEqual(0, adjacency_list[1][0].end) self.assertEqual(1, adjacency_list[1][0].weight) edges = graph.get_edges() self.assertEqual(2, len(edges)) self.assertListEqual([0, 1], sorted(map(lambda e: e.start, edges))) self.assertListEqual([0, 1], sorted(map(lambda e: e.end, edges))) self.assertListEqual([1, 1], sorted(map(lambda e: e.weight, edges)))
def test_returns_true_for_graph_with_multiple_connected_componenets(self): g = UndirectedGraph() g.add_edge(5, 2, 1) g.add_edge(4, 2, 1) g.add_edge(3, 4, 1) g.add_edge(1, 4, 1) g.add_edge(6, 7, 1) self.assertTrue(is_bipartite(g))
def test_returns_mst_for_graph_with_loops(self): graph = UndirectedGraph() graph.add_edge('A', 'B', 3) graph.add_edge('A', 'C', 4) graph.add_edge('D', 'B', 6) graph.add_edge('E', 'B', 2) graph.add_edge('B', 'C', 5) graph.add_edge('C', 'E', 7) mst = minimum_spanning_tree(graph.get_adjacency_list()) self.__compare_vertices(['A', 'B', 'C', 'D', 'E'], mst.get_adjacency_list()) self.__compare_edges([ Edge('A', 'B', 3), Edge('B', 'A', 3), Edge('B', 'E', 2), Edge('E', 'B', 2), Edge('A', 'C', 4), Edge('C', 'A', 4), Edge('B', 'D', 6), Edge('D', 'B', 6) ], mst.get_edges())
def test_does_not_change_tree(self): graph = UndirectedGraph() graph.add_edge(0, 1, 1) graph.add_edge(0, 6, 1) graph.add_edge(2, 3, 2) graph.add_edge(2, 4, 3) graph.add_edge(4, 5, 4) mst = minimum_spanning_tree(graph.get_adjacency_list()) self.__compare_vertices([0, 1, 2, 3, 4, 5, 6], mst.get_adjacency_list()) self.__compare_edges([ Edge(0, 1, 1), Edge(1, 0, 1), Edge(0, 6, 1), Edge(6, 0, 1), Edge(2, 3, 2), Edge(3, 2, 2), Edge(2, 4, 3), Edge(4, 2, 3), Edge(4, 5, 4), Edge(5, 4, 4) ], mst.get_edges())
def test_returns_true_for_graph_as_list(self): g = UndirectedGraph() g.add_edge(1, 2, 1) g.add_edge(2, 3, 1) self.assertTrue(is_bipartite(g))
def test_returns_single_edge_for_single_edge_in_graph(self): graph = UndirectedGraph() graph.add_edge(0, 1, 1) mst = minimum_spanning_tree(graph.get_adjacency_list()) self.__compare_vertices([0, 1], mst.get_adjacency_list()) self.__compare_edges([Edge(0, 1, 1), Edge(1, 0, 1)], mst.get_edges())