Comme aux TP précédents, nous aurons besoin de numpy
et de certaines de vos fonctions du TP1.
import numpy as np
from graph import *
Les graphes manipulés ici seront des 1-graphes non orientés, connexes et sans boucles.
Problèmatique :
Un problème de coloration consiste à affecter une couleur à chaque sommet d'un graphe de sorte que deux sommets voisins soient de couleurs différentes. L'objectif est de minimiser le nombre de couleurs utilisées.
color
¶Supposons g
, un graphe à n
sommets. La classe Graph
possède un attribut color
, qui est une liste de n
entiers. Au moment de l'affichage grâce à la méthode g.display()
, chaque entier de la liste g.color
est associé à une couleur.
Exemple :
g = Graph(directed=False)
g.successors = {0:{1,2,4,5},
1:{0,2,3},
2:{1,0,5},
3:{1},
4:{0},
5:{0,2}}
# par défaut, l'attribut color est une liste vide. Les sommets du graphe sont alors blancs
print("la liste des couleurs est :",g.color)
g.display()
la liste des couleurs est : []
liste_couleur = [5,2,2,1,7,4]
g.color = liste_couleur
print("la liste des couleurs est :",g.color)
g.display()
la liste des couleurs est : [5, 2, 2, 1, 7, 4]
Explication :
Attention !!
Un même entier ne sera pas toujours associé à la même couleur dans deux graphes différents !
Mais le plus grand entier donné sera toujours associé au magenta, les autres couleurs établissant une correspondance entre entiers et positions sur le spectre lumineux.
Le nombre 0 correpond lui au blanc : on l'utilisera comme absence de couleur.
g.color= [5,0,2,1,15,4]
print("la liste des couleurs est :",g.color)
g.display()
la liste des couleurs est : [5, 0, 2, 1, 15, 4]
exo1(g,[0,2,4])
g.display()
exo2(g,x)
qui qui colorie le graphe g
de la façon suivante : Exemple :
exo2(g,2)
g.display()
exo3(g)
qui qui colorie le graphe g
de la façon suivante : Exemple :
exo3(g)
g.display()
exo4(g,sommet,L)
permettant de colorer le sommet sommet
avec la couleur non blanche associée au plus petit entier qui n'est pas dans la liste L
.Exemple :
exo4(g,2,[1,4,5,2])
### le sommet 2 devrait être colorer avec la couleur 3
### (3 est bien le plus petit entier qui n'est pas dans [1,4,5,2])
g.color
[0, 0, 3, 0, 0, 0]
definition de glouton_simple(g) S = liste des sommets de g pour tout x de S pc = première couleur non utilisée par les voisins de x colorer le sommet x avec pc fin pour tout retourner g
Créer une fonction glouton_simple(g)
permettant de colorer un graphe g
grâce à l'algorithme glouton simplifié.
Tester glouton_simple(g)
.
Exemple :
glouton_simple(g)
g.display(title="G : glouton simple")
Assurez vous de bien obtenir une coloration cohérente !
g0.display(title="G0")
glouton_simple(g0)
g0.display(title="G0 : glouton simple")
La coloration obtenue est-elle optimale ?
g1.display(title="G1 : glouton simple")
glouton_simple(g1)
g1.display(title="G1 : glouton simple")
Grâce au mot clef lambda
, il est possible de créer à la volée des fonctions anonymes, c'est à dire des fonctions déclarées sans nom.
Sa syntaxe est : lambda arguments:expression
Les arguments peuvent être multiples, mais il n'y aura toujours qu'une seule expression
Exemples :
###Construisons une fonction qui calcule le carré d'un nombre
def carre(x):
return x**2
###la même chose avec une fonction lambda
lambda x : x**2
<function __main__.<lambda>(x)>
print(carre(3), (lambda x : x**2)(3))
9 9
###Construisons une fonction qui calcule la somme des carrés de deux nombres
def somme_carres(x,y):
return x**2 + y**2
###la même chose avecune fonction lambda
lambda x,y : x**2 + y**2
<function __main__.<lambda>(x, y)>
print(somme_carres(2,3), (lambda x,y : x**2 + y**2)(2,3))
13 13
La fonction sorted()
permet de trier une liste.
sorted([2,0,4,9,5]) #tri par ordre croissant, par défaut
[0, 2, 4, 5, 9]
sorted([2,0,4,9,5],reverse=True) #tri par ordre décroissant
[9, 5, 4, 2, 0]
sorted(["AB","AAA","A","BA","B"]) #tri par ordre alphabétique
['A', 'AAA', 'AB', 'B', 'BA']
La fonction sorted()
admet un paramètre optionnel key
.
Ce paramètre prend comme argument une fonction, qui va s'appliquer sur les valeurs de la liste à trier. Le tri se fait ensuite.
Exemples :
#Exemple 1
#tri suivant la longuer de la chaîne de caractère.
sorted(["AB","AAA","A","BA","B"], key=len)
['A', 'B', 'AB', 'BA', 'AAA']
#Exemple 2
#définition de la fonction qui calcule le reste dans la division euclidienne modulo 3
def modulo3(n):
return(n%3)
#tri suivant la valeur du reste modulo 3
sorted([2,0,4,9,5],key=modulo3)
[0, 9, 4, 2, 5]
#Exemple 3
#même exemple que ci-dessus, mais avec l'utilisation d'une fonction lambda
sorted([2,0,4,9,5],key= (lambda n : n%3) )
[0, 9, 4, 2, 5]
#Exemple 4
#tri suivant la distance de l'entier par rapport à 5
sorted([2,0,4,9,5],key= (lambda n : abs(n-5)) )
[5, 4, 2, 9, 0]
tri_degre(g,Bool)
qui renvoie la liste des sommets d'un graphe g
triés suivant leur degré (dans l'ordre décroissant si Bool = True
, croissant sinon).Exemple :
tri_degre(g1,True)
[3, 2, 4, 0, 1]
définition de glouton(g) S = liste ordonnée des sommets, suivant la valeur décroissante de leur degré. pour tout x de S pc = première couleur non utilisée par les voisins de x colorer le sommet x avec pc fin pour tout retourner g
glouton(g)
permettant de colorer un graphe g
grâce à l'algorithme glouton.Exemple :
glouton(g1)
g1.display(title="G1 : glouton")
On rappelle que : DSAT(x) = degré de saturation du sommet x = nombre de couleurs différentes dans les voisins de x
défintion de DSATUR(g) S = liste ordonnée des sommets, suivant la valeur décroissante de leur degré. colorer un des sommets de degré max avec la plus petite couleur tant que tous les sommets ne sont pas colorés choisir un sommet x non coloré avec un DSAT max (en cas d'égalité, choisir un sommet de degré max) pc = première couleur non encore utilisée par les voisins de x colorer le sommet x avec pc fin tant que retourner g
def dsatur(g):
n = g.size()
couleur = n*[0]
#liste des sommets par ordre de degrés décroissants
sommets_ord = tri_degre(g,True)
#tant qu'il y a des sommets sans couleur
while 0 in couleur:
#recherche du sommet à colorer, de degré de saturation maximum
dsat = n*[0]
degre_sat_max = 0
sommetchoisi = sommets_ord[0]
for i in sommets_ord:
#si le sommet i est sans couleur
if couleur[i]==0:
vois = g.successors[i]
#calcul du degré de saturation du sommet i
couleurvois = []
for k in vois:
if couleur[k]>0:
couleurvois = couleurvois+[couleur[k]]
dsat[i] = len(np.unique(couleurvois))
#le sommet i est-il de degre de saturation maximum ?
if dsat[i]>degre_sat_max :
degre_sat_max = dsat[i]
sommetchoisi = i
#couleur des voisins du sommet choisi
vois_sommetchoisi = g.successors[sommetchoisi]
couleurvois_sommetchoisi = []
for k in vois_sommetchoisi:
couleurvois_sommetchoisi = couleurvois_sommetchoisi+[couleur[k]]
#choix de la plus petite couleur non présente chez les voisins du sommet choisi
j=1
while j in couleurvois_sommetchoisi:
j=j+1
#coloration du sommet choisi avec la couleur trouvée ci-dessus
couleur[sommetchoisi]=j
g.color = couleur
return g
Copier l'algorithme ci-dessus.
Construire le graphe $g2$ ci-dessous :
g2.display(title="G2")
Trouver une coloration du graphe grâce à l'algorithme glouton simplifié.
Trouver une coloration du graphe grâce à l'algorithme glouton.
Trouver une coloration du graphe grâce à l'algorithme DSATUR.
glouton_simple(g2)
g2.display(title="G2 : glouton simple")
glouton(g2)
g2.display(title="G2 : glouton")
dsatur(g2)
g2.display(title="G2 : dsatur")
Un graphe est dit planaire ssi il existe une représentation de ce graphe où aucune arête n'en coupe une autre. Le théorème des 4 couleurs dit qu'un tel graphe peut être coloré avec au plus 4 couleurs.
on pourra utiliser la liste des pays ["Fr","Lux","Bel","All","PB","Sui","It"]
, à rentrer dans le paramètre label
de la méthode display
.
On considère le mini-sudoku de 16 cases suivant :
On cherche à remplir ce sudoku avec 4 couleurs en considérant les contraintes habituelles :
deux cases d'une même ligne ne peuvent pas avoir la même couleur
deux cases d'une même colonne ne peuvent pas avoir la même couleur
deux cases d'un même carré ne peuvent pas avoir la même couleur
On donne ci-dessous le graphe sud
à 16 sommets correspondant à une grille de mini-sudoku, sachant que deux sommets sont reliés ssi ils ne peuvent pas avoir la même couleur.
Exemple :
le sommet 0 est relié aux sommets 1, 2, 3, 4, 5, 8 et 12.
le sommet 10 est relié aux sommets 2, 6, 8, 9 ,11, 14 et 15.
sud = Graph(directed=False)
sud.successors = {0:{1,2,3,4,5,8,12}, 1:{0,2,3,4,5,9,13}, 2:{0,1,3,6,7,10,14}, 3:{0,1,2,6,7,11,15},
4:{0,1,5,6,7,8,12}, 5:{0,1,4,6,7,9,13}, 6:{2,3,4,5,7,10,14}, 7:{2,3,4,5,6,11,15},
8:{0,4,9,10,11,12,13}, 9:{1,5,8,10,11,12,13}, 10:{2,6,8,9,11,14,15}, 11:{3,7,8,9,10,14,15},
12:{0,4,8,9,13,14,15}, 13:{1,5,8,9,12,14,15}, 14:{2,6,10,11,12,13,15}, 15:{3,7,10,11,12,13,14}}
DSATUR
donné plus haut, construire une fonction sudoku(sommets, couleurs)
, qui propose une coloration du sudoku, en respectant les contraintes initiales suivantes : sommets
contient la liste de sommets initialement colorés couleurs
contient la liste des couleurs associées aux sommets précédents.Exemple :
#dans l'exemple de l'illustration ci-dessus, les sommets déja colorés sont les sommets 0,2,4,11 et 13, associés aux couleurs 1,2,3,4 et 1
sudoku([0,2,4,11,13],[1,2,3,4,1]).display()
sudoku_tableau(sommets, couleurs)
qui propose une représentation du sudoku sous forme de tableau 4 par 4.Exemple :
#Affichage du sudoku résolu
sudoku_tableau([0,2,4,11,13],[1,2,3,4,1])
array([[1., 4., 2., 3.], [3., 2., 4., 1.], [2., 3., 1., 4.], [4., 1., 3., 2.]])