La largeur d' arbre d'un graphe non orienté est un concept très important en théorie des graphes. Des tonnes d'algorithmes de graphe ont été inventés qui fonctionnent rapidement si vous avez une décomposition du graphe avec une petite largeur d'arbre.
La largeur d'arbre est souvent définie en termes de décompositions d'arbre. Voici un graphique et une décomposition arborescente de ce graphique, gracieuseté de Wikipedia:
Une décomposition d'arbre est un arbre où chaque sommet est associé à un sous-ensemble des sommets du graphe d'origine, avec les propriétés suivantes:
- Chaque sommet du graphique d'origine se trouve dans au moins l'un des sous-ensembles.
- Chaque arête du graphique d'origine possède ses deux sommets dans au moins l'un des sous-ensembles.
- Tous les sommets de la décomposition dont les sous-ensembles contiennent un sommet d'origine donné sont connectés.
Vous pouvez vérifier que la décomposition ci-dessus respecte ces règles. La largeur d'une décomposition d'arbre est la taille de son plus grand sous-ensemble, moins un. Par conséquent, c'est deux pour la décomposition ci-dessus. La largeur d'arbre d'un graphique est la plus petite largeur de toute décomposition d'arbre de ce graphique.
Dans ce défi, vous recevrez un graphique connecté et non orienté, et vous devez trouver sa largeur d'arbre.
Bien qu'il soit difficile de trouver des décompositions d'arbre, il existe d'autres façons de calculer la largeur d'arbre. La page Wikipedia contient plus d'informations, mais une méthode de calcul de la largeur d'arbre qui n'y est pas mentionnée et qui est souvent utilisée dans les algorithmes pour calculer la largeur d'arbre est la largeur de classement d'élimination minimale. Voir ici pour un article utilisant ce fait.
Dans un ordre d'élimination, on élimine tous les sommets d'un graphe un par un. Lorsque chaque sommet est éliminé, des arêtes sont ajoutées reliant tous les voisins de ce sommet les uns aux autres. Ceci est répété jusqu'à ce que tous les sommets aient disparu. La largeur d'ordre d'élimination est le plus grand nombre de voisins que tout sommet qui est éliminé a au cours de ce processus. La largeur d'arbre est égale au minimum sur tous les ordres de la largeur d'ordre d'élimination. Voici un exemple de programme utilisant ce fait pour calculer la largeur d'arbre:
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))
Exemples:
[(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
Vous recevrez le graphique en entrée et vous devrez renvoyer la largeur d'arbre en sortie. Le format d'entrée est flexible. Vous pouvez prendre une liste d'arêtes, une carte d'adjacence ou une matrice d'adjacence en entrée. Si vous souhaitez utiliser un autre format d'entrée, demandez dans les commentaires. Vous pouvez supposer que l'entrée est connectée, et vous pouvez construire cette hypothèse dans votre format d'entrée, par exemple en utilisant une liste de bords.
EDIT: les opérations intégrées qui calculent la largeur d'arbre ne sont pas autorisées. Je m'excuse de ne pas l'avoir précisé à l'avance.
Le code le plus court gagne.
la source
(V,E)
-ce que ce serait une entrée valide?Réponses:
Octave, 195 octets
Une fonction qui prend en entrée une matrice d'adjacence. Il consomme beaucoup de mémoire, il est donc inutile si le nombre de sommets est supérieur à 10-12.
endfunction
mais il doit être ajouté à tio.Essayez-le en ligne!
Non golfé:
la source
SageMath,
29 octetsnon compétitifs ** Cette réponse a été publiée avant le changement par OP de la question "Les buildins sont interdits", donc je l'ai rendue non compétitive.
Démo en ligne!
la source
Haskell (Lambdabot),
329321245 octetsVoici ma solution, grâce à la flexibilité de l'entrée, elle fonctionne sur les graphiques avec des graphiques contenant n'importe quel type qui est une instance de
Eq
.Essayez-le en ligne!
Version non golfée:
la source