Trouver le numéro chromatique


13

Étonnamment, nous n'avons pas encore eu de défis sur la coloration des graphiques!

Étant donné un graphe non orienté, nous pouvons donner à chaque sommet une couleur telle que deux sommets adjacents ne partagent pas la même couleur. Le plus petit nombre χ de couleurs distinctes nécessaires pour y parvenir est appelé numéro chromatique du graphique.

Par exemple, ce qui suit montre une coloration valide utilisant le nombre minimum de couleurs:

(Trouvé sur Wikipedia)

Le nombre chromatique de ce graphique est donc χ = 3 .

Écrivez un programme ou une fonction qui, étant donné un nombre de sommets N <16 (qui sont numérotés de 1 à N ) et une liste d'arêtes, détermine le nombre chromatique d'un graphique.

Vous pouvez recevoir l'entrée et produire la sortie dans n'importe quel format approprié, tant que l'entrée n'est pas prétraitée. Autrement dit, vous pouvez utiliser une chaîne ou un tableau, ajouter des délimiteurs pratiques à la chaîne ou utiliser un tableau imbriqué, mais quoi que vous fassiez, la structure aplatie doit contenir les mêmes numéros que les exemples ci-dessous (dans le même ordre).

Vous ne pouvez pas utiliser les fonctions intégrées liées à la théorie des graphes (comme celles de Mathematica ChromaticNumber).

Vous pouvez supposer que le graphique n'a pas de boucle (un bord reliant un sommet à lui-même) car cela rendrait le graphique incolore.

Il s'agit du code golf, la réponse la plus courte (en octets) l'emporte.

Exemples

Votre programme doit au moins résoudre tous ces problèmes dans un délai raisonnable. (Il doit résoudre correctement toutes les entrées, mais cela peut prendre plus de temps pour les entrées plus grandes.)

Pour raccourcir le message, dans les exemples suivants, je présente les bords dans une seule liste séparée par des virgules. Si vous préférez, vous pouvez utiliser des sauts de ligne ou attendre l'entrée dans un format de tableau pratique.

Triangle (χ = 3)

3
1 2, 2 3, 1 3

"Anneau" de 6 sommets (χ = 2)

6
1 2, 2 3, 3 4, 4 5, 5 6, 6 1

"Anneau" de 5 sommets (χ = 3)

5
1 2, 2 3, 3 4, 4 5, 5 1

Exemple d'image ci-dessus (χ = 3)

6
1 2, 2 3, 3 4, 4 5, 5 6, 6 1, 1 3, 2 4, 3 5, 4 6, 5 1, 6 2

Généralisation de ce qui précède pour 7 sommets (χ = 4)

7
1 2, 2 3, 3 4, 4 5, 5 6, 6 7, 7 1, 1 3, 2 4, 3 5, 4 6, 5 7, 6 1, 7 2

Graphique de Petersen (χ = 3)

10
1 2, 2 3, 3 4, 4 5, 5 1, 1 6, 2 7, 3 8, 4 9, 5 10, 6 8, 7 9, 8 10, 9 6, 10 7

Graphique complet de 5 sommets, plus un sommet déconnecté (χ = 5)

6
1 2, 1 3, 1 4, 1 5, 2 3, 2 4, 2 5, 3 4, 3 5, 4 5

Graphique complet de 8 sommets (χ = 8)

8
1 2, 1 3, 1 4, 1 5, 1 6, 1 7, 1 8, 2 3, 2 4, 2 5, 2 6, 2 7, 2 8, 3 4, 3 5, 3 6, 3 7, 3 8, 4 5, 4 6, 4 7, 4 8, 5 6, 5 7, 5 8, 6 7, 6 8, 7 8

Réseau triangulaire à 15 sommets (χ = 3)

15
1 2, 1 3, 2 3, 2 4, 2 5, 3 5, 3 6, 4 5, 5 6, 4 7, 4 8, 5 8, 5 9, 6 9, 6 10, 7 8, 8 9, 9 10, 7 11, 7 12, 8 12, 8 13, 9 13, 9 14, 10 14, 10 15, 11 12, 12 13, 13 14, 14 15

Pourriez-vous définir raisonnable? 1 minute? dix?
ThreeFx

@ThreeFx oui, 10 minutes sont raisonnables. une demi-journée ne l'est pas. Je ne veux pas être trop rigoureux sur la limite, car alors je dois tout tester à nouveau sur la même (ma) machine. mais disons que si cela se termine en une heure sur votre machine, ça va.
Martin Ender

Réponses:


4

Python 2.7 - 122 109 111 111 109 108 103

f=lambda n,e,m=1:any(all(t*m//m**a%m!=t*m//m**b%m for(a,b)in e)for t in range(m**n))and m or f(n,e,m+1)

Usage:

print f(5, [(1, 2), (2, 3), (3, 4), (4, 5), (5, 1)])

Force brute en augmentant le nombre chromatique (m) et vérifiez toutes les colorations possibles. Une coloration peut être décrite comme un nombre en base m. Les colorations possibles sont donc 0, 1, ..., m ^ n-1.

edit: Le graphe complet de 8 sommets prend assez de temps. Mais mon ordinateur portable le résout en environ 10 minutes. Les autres cas de test ne prennent que quelques secondes.


edit 2: Lire que le prétraitement est autorisé, je laisse donc l'index des sommets commencer par 0: raccourcit t * m // m ** x% m en t // m ** a% m (-2). Dissoudre lambda et mettre m dans les paramètres de fonction (-11)


edit 3: le prétraitement n'est pas autorisé -> retour à t * m (+4), simplifié // à / (-2).


modifier 4: supprimer les crochets dans n'importe quel (-2), merci xnor.


edit 5: au lieu de prendre deux fois modulo m, il suffit de les soustraire et ensuite d'utiliser modulo (-1). Il s'agit également d'une amélioration des performances. Tous les tests prennent ensemble environ 25 secondes sur mon ordinateur portable.


edit 6: appel récursif au lieu de while 1: et m + = 1 (-5). Merci encore, xnor.


Belle méthode. Un simple golf: vous pouvez supprimer les parenthèses dans all([...])si vous encassez les parenthèses a,b(ce qui ne coûte aucun caractère ici en raison de l'espacement) afin de allne pas les confondre avec des arguments supplémentaires. En outre, je soupçonne que vous pouvez enregistrer des caractères si vous recursez avec un appel de fonction au niveau msupérieur suivant plutôt que d'utiliser une boucle while.
xnor

Merci, l'approche récursive prend cependant +2 caractères. Une approche pour m dans la plage (n + 1) également.
Jakube

J'optimise la démarche récursive un peu avec anyet l' and/orastuce, puis il enregistre quelques caractères: f=lambda n,e,m=1:any(all(t*m//m**a%m!=t*m//m**b%m for(a,b)in e)for t in range(m**n))and m or f(n,e,m+1).
xnor

2

Java - 241 218

int k,j,c;int f(int n,int[]e){for(k=1;k<=n;k++)for(long p=0;p<x(n);p++){for(j=0,c=0;j<e.length;c=p%x(e[j])/x(e[j]-1)==p%x(e[j+1])/x(e[j+1]-1)?1:c,j+=2);if(c<1)return k;}return 0;}int x(int a){return(int)Math.pow(k,a);}

La façon la plus évidente de le faire étant donné les contraintes est la force brute. Parcourez chaque numéro chromatique ket attribuez chaque couleur à chaque sommet. Si aucun voisin n'est de la même couleur, vous avez votre numéro. Sinon, continuez.

Cela prend le plus de temps pour le cas de test χ = 8(les graphiques complets sont nulles ici), mais c'est toujours sous 15 secondes (ok, environ 100s avec la dernière modification).

L'entrée est le nombre de sommets net un tableau de sommets d'arêtes e[]donnés dans le même ordre que les valeurs séparées par des virgules OP.

Avec des sauts de ligne:

int k,j,c;
int f(int n,int[]e){
    for(k=1;k<=n;k++)
        for(long p=0;p<x(n);p++){
            for(j=0,c=0;
                j<e.length;
                c=p%x(e[j])/x(e[j]-1)==p%x(e[j+1])/x(e[j+1]-1)?1:c,
                j+=2);
            if(c<1)return k;
        }
    return 0;
}
int x(int a){return(int)Math.pow(k,a);}

Oh, et cela suppose que l'entrée est une sorte de graphique colorable. Si une arête passe de v1 à v1, ou s'il n'y a pas de sommets, elle ne peut pas être colorée et affichera 0. Cela fonctionnera toujours pour les graphiques sans arêtes χ=1, etc.


2

Python 3 - 162

Utilise la même approche par force brute, mais utilise la bibliothèque itertools pour, espérons-le, une génération de combinaisons plus rapide. Résout le graphique complet de 8 en <1 min sur ma machine assez ordinaire.

import itertools as I
def c(n,v):
 for i in range(1,n+1):
  for p in I.product(range(i),repeat=n):
   if(0==len([x for x in v if(p[x[0]]==p[x[1]])])):return i

Exemple d'utilisation pour le cas complet à 8 graphiques:

print(c(8,[x for x in I.combinations(range(8), 2)]))

1

Haskell, 163 octets

p x=f(length x)(transpose x)1
f a[b,c]d|or$map(\x->and$g x(h b)(h c))(sequence$replicate a[1..d])=d|0<1=f a b c(d+1)
g a=zipWith(\x y->a!!x/=a!!y)
h=map(flip(-)1)

L'utilisation serait comme ceci:

p [[1, 2],[2, 3],[3, 1]]

Approche de base de la force brute. Vérifiez toutes les combinaisons de couleurs possibles si elles sont valides. Pas grand-chose d'autre à dire ici, sauf que je suis heureux d'entendre des conseils pour raccourcir cela encore plus;)


Je dirais que décrémenter les sommets et les transposer compte comme du "prétraitement". Ce que j'avais à l'esprit avec "n'importe quel format pratique" était plutôt que vous pouviez choisir parmi une liste plate, une liste imbriquée, une chaîne, une chaîne avec des délimiteurs pratiques, etc ... mais la structure aplatie devrait être la même que celle spécifiée dans le défi.
Martin Ender

@ MartinBüttner Très bien, je vais le changer
ThreeFx

@ThreeFx all idest identique à and, any idest identique à oret any id$map f listest identique à juste any f list. vous pouvez également faire quelques choses avec g: vous pouvez le redéfinir en tant que g a=(and.).zipWith(\x y->a!!x/=a!!y), le rendre infixé, changer l'ordre d'entrée pour le remplacer (\x->g x b c)par g b cou même le rendre complètement sans points et l'intégrer. certains d'entre eux ne fonctionnent pas ensemble, alors essayez-les tous et choisissez le meilleur :)
fier haskeller

1
@ MartinBüttner Je pense que c'est fixe, au coût de maaaaany octets. : D
ThreeFx

1
Comment résolvez-vous le 7ème exemple sans le nombre de sommets dans l'entrée?
Martin Ender
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.