El ancho de árbol de un gráfico no dirigido es un concepto muy importante en la teoría de gráficos. Se han inventado toneladas de algoritmos de gráficos que se ejecutan rápidamente si tiene una descomposición del gráfico con un ancho de árbol pequeño.
El ancho del árbol a menudo se define en términos de descomposiciones del árbol. Aquí hay un gráfico y una descomposición en árbol de ese gráfico, cortesía de Wikipedia:
La descomposición de un árbol es un árbol donde cada vértice está asociado con un subconjunto de los vértices del gráfico original, con las siguientes propiedades:
- Cada vértice en el gráfico original está en al menos uno de los subconjuntos.
- Cada borde en el gráfico original tiene sus dos vértices en al menos uno de los subconjuntos.
- Todos los vértices en la descomposición cuyos subconjuntos contienen un vértice original dado están conectados.
Puede verificar que la descomposición anterior sigue estas reglas. El ancho de la descomposición de un árbol es el tamaño de su subconjunto más grande, menos uno. Por lo tanto, son dos para la descomposición anterior. El ancho de árbol de un gráfico es el ancho más pequeño de cualquier descomposición de árbol de ese gráfico.
En este desafío, se le dará un gráfico conectado, no dirigido, y deberá encontrar su ancho de árbol.
Si bien encontrar descomposiciones de árboles es difícil, existen otras formas de calcular el ancho del árbol. La página de Wikipedia tiene más información, pero un método para calcular el ancho de árbol que no se menciona allí y que a menudo se usa en algoritmos para calcular el ancho de árbol es el ancho mínimo de orden de eliminación. Vea aquí un artículo que utiliza este hecho.
En un orden de eliminación, uno elimina todos los vértices de un gráfico de uno en uno. Cuando se elimina cada vértice, se agregan bordes conectando todos los vecinos de ese vértice entre sí. Esto se repite hasta que todos los vértices hayan desaparecido. El ancho de orden de eliminación es el mayor número de vecinos que tiene cualquier vértice que se está eliminando durante este proceso. El ancho de árbol es igual al mínimo en todos los pedidos del ancho de orden de eliminación. Aquí hay un programa de ejemplo que usa este hecho para calcular el ancho del árbol:
import itertools
def elimination_width(graph):
max_neighbors = 0
for i in sorted(set(itertools.chain.from_iterable(graph))):
neighbors = set([a for (a, b) in graph if b == i] + [b for (a, b) in graph if a == i])
max_neighbors = max(len(neighbors), max_neighbors)
graph = [edge for edge in graph if i not in edge] + [(a, b) for a in neighbors for b in neighbors if a < b]
return max_neighbors
def treewidth(graph):
vertices = list(set(itertools.chain.from_iterable(graph)))
min_width = len(vertices)
for permutation in itertools.permutations(vertices):
new_graph = [(permutation[vertices.index(a)], permutation[vertices.index(b)]) for (a, b) in graph]
min_width = min(elimination_width(new_graph), min_width)
return min_width
if __name__ == '__main__':
graph = [('a', 'b'), ('a', 'c'), ('b', 'c'), ('b', 'e'), ('b', 'f'), ('b', 'g'),
('c', 'd'), ('c', 'e'), ('d', 'e'), ('e', 'g'), ('e', 'h'), ('f', 'g'), ('g', 'h')]
print(treewidth(graph))
Ejemplos:
[(0, 1), (0, 2), (0, 3), (2, 4), (3, 5)]
1
[(0, 1), (0, 2), (1, 2), (1, 4), (1, 5), (1, 6), (2, 3), (2, 4), (3, 4), (4, 6), (4, 7), (5, 6), (6, 7)]
2
[(0, 1), (0, 3), (1, 2), (1, 4), (2, 5), (3, 4), (3, 6), (4, 5), (4, 7), (5, 8), (6, 7), (7, 8)]
3
[(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
4
Recibirá el gráfico como entrada y deberá devolver el ancho del árbol como salida. El formato de entrada es flexible. Puede tomar una lista de aristas, un mapa de adyacencia o una matriz de adyacencia como entrada. Si desea utilizar otro formato de entrada, pregunte en los comentarios. Puede suponer que la entrada está conectada, y puede construir esa suposición en su formato de entrada, por ejemplo, utilizando una lista de bordes.
EDITAR: Las operaciones integradas que calculan el ancho del árbol no están permitidas. Pido disculpas por no especificar esto por adelantado.
El código más corto gana.
(V,E)
¿sería una entrada válida?