def bipartite( g: Graph) -> Optional[Tuple[List[Graph.Vertex], List[Graph.Vertex]]]: """ La funzione bipartite() prende in input un grafo G non diretto, verifica se G è bipartito e restituisce una partizione (X, Y) dei vertici di G tale che tutti gli archi del grafo collegano un vertice di X ad un vertice di Y. :param g: grafo non orientato :return: partizione (X, Y) o None se il grafo non è bipartibile """ visited = set() # Insieme dei vertici visitati x = [] # init partizione 1 y = [] # init partizione 2 for u in g.vertices(): # per ogni vertice del grafo if u not in visited: # che non ho ancora visitato visited.add(u) # lo segno come visitato result = bipartite_connected( g, u, visited ) # calcolo bipartite della componente connessa del grafo # in cui si trova il vertice if result is not None: # se la componente connessa è bipartibile x = x + result[0] # aggiorno la partizione 1 y = y + result[1] # aggiorno la partizione 2 else: # altrimenti return None # il grafo non è bipartibile return x, y # restituisco le partizioni
def graph_randomize(n: int): graph = Graph() random = Random() for i in range(0, n): graph.insert_vertex(i) for v in graph.vertices(): for u in graph.vertices(): if bool(random.getrandbits(1)) and u != v and graph.get_edge( u, v) is None: graph.insert_edge(u, v) print("number of vertices " + str(graph.vertex_count()) + "\nnumber of edges " + str(graph.edge_count())) return graph
def bipartite(G: Graph): """ La funzione verifica se G è bipartito e restituisce una partizione (X, Y) dei vertici di G tale che tutti gli archi del grafo collegano un vertice di X ad un vertice di Y. Nel caso in cui il grafo non sia bipartito la funzione deve restituire None. :param G: grafo non diretto da ispezionare :return: None se il grafo non è bipartito, altrimenti una sua partizione Il problema corrisponde alla verifica della k-colorabilità di un grafo, cioè verificare se è possibile, dato un grafo non diretto, colorarlo con al più k colori in modo che non esistano due vertici adiacenti dello stesso colore. Nel caso il problema si riduce alla 2-colorabilità. La complessità computazionale è la stessa della DFS completa, e cioè O(n+m), siccome la classe Graph rappresenta il grafo utilizzando liste di adiacenza, in cui n è il numero di vertici ed m il numero di archi. """ discovered = {} # dizionario per tenere traccia dei nodi visitati color = {} # dizionario per tenere traccia dei colori dei nodi X = set() # partizioni del grafo Y = set() partition = None for node in G.vertices(): # inizializza i colori dei nodi if node not in color: color[node] = False for v in G.vertices(): # tiene conto di grafi non connessi if v not in discovered: partition = color_dfs(G, v, discovered, color) if partition is None: return partition if partition is not None: # popola le due partizioni del grafo for x in partition.items(): if x[1] is True: X.add(x[0]) else: Y.add(x[0]) return X, Y else: return partition
def complete_bipartite(graph: Graph): """ :param graph: grafo non diretto :returns: True/False se il grafo è bipartito o meno, x e y come partizioni contenenti i nodi (se bipartito) """ discover = {} x = [] y = [] for vertex in graph.vertices(): if vertex not in discover: discover[vertex] = 0 x.append(vertex) if not bipartite(graph, vertex, x, y, discover): return False, None, None return True, x, y
def bacefook_greedy_algorithm(graph: Graph): """ greedy algorithm to compute the minimum number of nodes with software map structure: -Key store all vertices of the graph -Value is a dict dict structure: -token store locator from priority queue -so_sw_count store the number of adj nodes -has_sw bool if the node has the software Priority queue store all the nodes of the graph ordered by number of adj nodes """ priority_queue = AdaptableHeapPriorityQueue() map = {} for v in graph.vertices(): token = priority_queue.add(-graph.degree(v), v) map[v] = { 'token': token, 'no_sw_count': graph.degree(v), 'has_sw': False } for i in range(0, graph.vertex_count()): k, v = priority_queue.remove_min() if graph.degree(v) == 0: continue if k == 0: break map[v]['has_sw'] = True for e in graph.incident_edges(v): adj_v = e.opposite(v) if not map[adj_v]['has_sw']: map[adj_v]['no_sw_count'] -= 1 priority_queue.update(map[adj_v]['token'], -map[adj_v]['no_sw_count'], adj_v) return {v._element: map[v]['has_sw'] for v in map}