A largura de árvore de um gráfico não direcionado é um conceito muito importante na Teoria dos Graficos. Foram inventadas toneladas de algoritmos de gráficos que são executados rapidamente se houver uma decomposição do gráfico com pequena largura de árvore.
A largura da árvore é geralmente definida em termos de decomposições de árvores. Aqui está um gráfico e uma decomposição em árvore desse gráfico, cortesia da Wikipedia:
Uma decomposição em árvore é uma árvore em que cada vértice está associado a um subconjunto dos vértices do gráfico original, com as seguintes propriedades:
- Cada vértice no gráfico original está em pelo menos um dos subconjuntos.
- Cada aresta no gráfico original possui ambos os vértices em pelo menos um dos subconjuntos.
- Todos os vértices na decomposição cujos subconjuntos contêm um determinado vértice original estão conectados.
Você pode verificar se a decomposição acima segue essas regras. A largura de uma decomposição de árvore é do tamanho de seu maior subconjunto, menos um. Portanto, são dois para a decomposição acima. A largura da árvore de um gráfico é a menor largura de qualquer decomposição de árvore desse gráfico.
Nesse desafio, você receberá um gráfico conectado e não direcionado e deverá encontrar a largura da árvore.
Embora seja difícil encontrar decomposições de árvores, há outras maneiras de calcular a largura da árvore. A página da Wikipedia tem mais informações, mas um método de calcular a largura da árvore não mencionado lá, que é frequentemente usado em algoritmos para calcular a largura da árvore, é a largura mínima para pedidos de eliminação. Veja aqui um artigo sobre esse fato.
Em uma ordem de eliminação, elimina-se todos os vértices de um gráfico, um de cada vez. Quando cada vértice é eliminado, as arestas são adicionadas conectando todos os vizinhos desse vértice. Isso é repetido até todos os vértices desaparecerem. A largura da ordem de eliminação é o maior número de vizinhos que qualquer vértice que está sendo eliminado possui durante esse processo. A largura da árvore é igual ao mínimo em todos os pedidos da largura do pedido de eliminação. Aqui está um exemplo de programa usando esse fato para calcular a largura da árvore:
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))
Exemplos:
[(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
Você receberá o gráfico como entrada e deverá retornar a largura da árvore como saída. O formato de entrada é flexível. Você pode usar uma lista de arestas, um mapa de adjacência ou uma matriz de adjacência como entrada. Se você quiser usar outro formato de entrada, pergunte nos comentários. Você pode assumir que a entrada está conectada e pode construir essa suposição no seu formato de entrada, por exemplo, usando uma lista de arestas.
EDIT: Operações internas que calculam a largura da árvore não são permitidas. Peço desculpas por não especificar isso com antecedência.
O menor código vence.
fonte
(V,E)
, isso seria uma entrada válida?Respostas:
Oitava, 195 bytes
Uma função que assume como entrada uma matriz de adjacência. Consome grande quantidade de memória e, portanto, é inútil se o número de vértices for maior que 10-12.
endfunction
entanto, ele deve ser adicionado ao tio.Experimente online!
Ungolfed:
fonte
SageMath,
29 bytesnão- concorrentes ** Esta resposta foi postada antes da mudança do OP da pergunta "Builtins is banned", então eu a tornei não-competitiva.
Demonstração Online!
fonte
Haskell (Lambdabot),
329321245 bytesAqui está minha solução, graças à flexibilidade da entrada que funciona em gráficos com gráficos contendo qualquer tipo de instância
Eq
.Experimente online!
Versão não destruída:
fonte