Académique Documents
Professionnel Documents
Culture Documents
examAP2 2212PT
examAP2 2212PT
Examen N°1
Matière Nombre de pages durée Classes
Informatique 8 2h 2ième Cycle préparatoire
NB : Si un candidat est amené à repérer ce qui peut lui sembler être une erreur d’énoncé, il le signalera sur sa
copie et devra poursuivre sa composition en expliquant les raisons des initiatives qu’il a été amené à prendre.
Problème : . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 points
Partie I : Modélisation Objet d’un système de transport . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 points
On souhaite modéliser en PYTHON le calcul de coûts de transport de marchandises. Les marchandises transpor-
tées seront des instances de la classe Marchandise dont la description est la suivante :
Les marchandises sont transportées sous la forme de cargaisons. Une cargaison est caractérisée par la distance sur
laquelle elle est transportée.
TRAVAIL A FAIRE :
I.1. Définir la classe Marchandise :
I.1.a. Implémenter la méthode __init__. 1 point
I.1.b. Implémenter la méthode __repr__. 1 point
Solution:
Classe Marchandise
class Marchandise:
def __repr__(self):
return "Marchandise({!r}, {}, {})".format(self.ref, self.poids, self.volume)
Solution:
Page 2
Classe Cargaison
class Cargaison:
ids = 0
def __init__(self, distance):
self.id = Cargaison.ids
Cargaison.ids += 1
self.data = list()
self.distance = distance
def __str__(self):
return "Cargaison {}".format(self.data)
def __len__(self):
return len(self.data)
def volumeTotal(self):
return sum(m.volume for m in self.data)
def poidsTotal(self):
return sum(m.poids for m in self.data)
I.3. Définir les classes Fluviale, Routière, Aérienne , dérivées de la classe mère Cargaison. En redéfinissant 3 points
uniquement les méthodes nécessaires pour vérifier l’encombrement et mesurer le cout du transport.
Solution:
Page 3
Classes Fluviale, Routière et Aérienne
class Fulviale(Cargaison):
def cout(self):
return self.distance * self.poidsTotal()
class Routière(Cargaison):
def cout(self):
return 4 * self.distance * self.poidsTotal()
class Aérienne(Cargaison):
def cout(self):
return 10 * self.distance * self.volumeTotal()
I.4. Définir la classe AérienneUrgente dérivée de la classe mère Aérienne. Redéfinir la ou les méthode(s) néces- 1 point
saires.
Solution:
Classe AérienneUrgente
class AérienneUrgente(Aérienne):
def cout(self):
return 2 * super().cout()
Page 4
Partie II : Optimisation de transport des cargaisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 points
La compagnie de transport envisage d’utiliser une stratégie pour optimiser le chargement des cargaisons dans les
différents véhicules de transport. Pour cette finalité, les cargaisons sont regroupées en fonction de leurs destinations
et suivant les différentes escales des véhicules. Étant donné un ensemble de cargaisons de même classe (Fluviale,
Routière, Aérienne ou AérienneUrgente) ayant des destinations compatibles et pouvant ainsi être chargée dans le
même véhicule. L’objectif de cette partie est de trouver un sous-ensemble de cargaison permettant de maximiser
le profit du voyage (total des coûts de transport des cargaisons) tout en respectant les contraintes de capacités
relatives au volume et au poids total pouvant être pris en charge par ce véhicule. Formellement, étant donné un
ensemble de cargaisons :
ec = {c1 , c2 . . . , cn }
L’objectif est de trouver les variables de décision xi ∈ {0, 1} ∀ i = 1 . . . n.
(
xi = 1 ⇔ La cargaison ci doit être chargée dans le voyage courant
Avec :
xi = 0 ⇔ La cargaison ci n’est pas considérée dans le voyage courant
Les valeurs xi doivent maximiser le profit :
n
X
xi ci .cout()
i=1
Tout en respectant les contraintes de capacités limites du véhicule :
n
X
xi ci .poidsTotal() ≤ W : contrainte de capacité limite en poids.
i=0
n
X
xi ci .volumeTotal() ≤ V : contrainte de capacité limite en volume.
i=0
Où W et V sont des quantités réelles positives désignant respectivement le poids limite et le volume limite que le
véhicule concerné peut prendre en charge.
— v est le volume limite encore disponible : v = V − volume des cargaisons déjà prises en charge. .
P
L’objectif de cette partie est d’implémenter une classe CargoOptimizer qui combine la démarche récursive précé-
dente avec la technique de mémoïsation pour trouver le sous-ensemble de cargaisons optimal. La description de
cette classe est comme suit :
Page 5
Nom Type Rôle
Attributs items list Une liste de cargaisons de même classe, représentant les éléments de l’ensemble des car-
d’instance gaisons de décision ec.
cache dict Un dictionnaire, où :
— Chaque clé est un tuple (i, w, v) représentant un état dans l’espace d’optimisation.
— Chaque valeur est un réel P(i,w,v) calculé suivant la démarche récursive ci-haut.
x list Une liste de booléens ayant la même taille que items correspondant aux variables de
décisions. xi = 1 ⇔ (self.x[i-1] = True) et réciproquement.
Nom de la méthode Rôle
__init__ Le constructeur permettant d’initier l’instance courante à partir d’une liste contenant les
cargaisons de décision {c1 . . . cn }. L’attribut items doit contenir une copie de cette liste,
cache est initialisé par un dictionnaire vide et x à une liste de booléens qui valent False.
Méthodes __getitem__ Prend un int i et retourne la cargaison ci d’indice i-1 de items. self[i] ⇔
self.items[i-1].
reset Permet de réinitialiser le contenu de dictionnaire cache à un dictionnaire vide.
expand_state Méthode récursive qui prend 3 paramètres i, w, v. Elle effectue l’appel du schéma
récursif expliqué ci-haut uniquement si le tuple t = (i,w,v) n’est pas présent
dans cache. Le résultat de cet appel est associé à la clé t puis inséré dans le
dictionnaire cache. La valeur cache[t] est finalement retournée par la fonction.
N. B. Pour générer tous les états possibles, appeler cette fonction avec l’état initial
(n, W, V).
fit Prend en entrée deux paramètres W et V correspondant aux poids limite et au volume
limite du véhicule. Elle remplit le dictionnaire cache par les différentes configurations
possibles d’états (i, w, v) et leurs profits associés, après l’avoir réinitialisé.
deduce C’est une méthode récursive qui représente la phase de déduction (calcul des xi ) elle
prend en entrée 3 paramètres i, w et v décrivant un état d’optimisation et permet de
remplir la liste x comme suit :
Condition d’arrêt : i = 0
Cas récursifs : soit α = cache[i, w, v] et ᾱ = cache[i-1, w, v]
si α ≥ ᾱ alors xi ← True, puis poursuivre la déduction récursivement à partir de
l’état (i-1, w- ci .poidsTotal(), v- ci .volumeTotal())
sinon xi ← False, puis poursuivre la déduction à partir de l’état (i-1, w, v).
N. B. Pour calculer toutes les xi , appeler cette fonction avec l’état initial (n, W, V).
get_idx Prend en entrée deux paramètres W et V représentant les capacités limites en poids et
en volume du véhicule. Cette fonction applique la méthode de déduction pour remplir
la liste x des variables de décision puis retourne un ensemble contenant les indices des
cargaisons qui seront chargées dans le véhicule.
__call__ Prend en entrée deux paramètres W et V représentant respectivement les capacités limites
en poids et en volume du véhicule. Cette fonction applique les étapes suivantes :
(i) Remplit le dictionnaire cache par tous les états possibles d’optimisation avec leurs
profits associés.
(ii) Retourne un tuple contenant deux éléments : la valeur optimale du profit et une liste
des cargaisons qui seront transportées par le véhicule.
TRAVAIL A FAIRE :
II.1. Définir la classe CargoOptimizer :
II.1.a. Définir la méthode __init__. 1 point
II.1.b. Définir la méthode __getitem__. 1 point
II.1.c. Définir la méthode reset. 1 point
II.1.d. Définir la méthode expand_state. 1 point
II.1.e. Définir la méthode fit. 1 point
II.1.f. Définir la méthode deduce. 1 point
II.1.g. Définir la méthode get_idx. 1 point
II.1.h. Définir la méthode __call__. 1 point
Page 6
Solution:
Classe CargoOptimizer
class CargoOptimizer:
def __init__(self, lst):
self.items = lst.copy()
self.cache = {}
self.x = [False] * len(lst)
def reset(self):
self.cache = {}
Page 7
Annexe
Le tableau suivant contient quelques méthodes utiles que l’étudiant peut éventuellement utiliser pour la composition
de ses réponses.
méthode/fonction rôle exemple
la classe str
str.format retourne un str résultant de la sub- " {} + {} = {}".format(1,1,2)
stitution des motifs par ses para- donne "1 + 1 = 2"
mètres
str.replace Retourne un nouvel str contenant str(list(range(5))).replace(",", " ")
où chaque occurrence du motif old donne '[0 1 2 3 4]'
est substitué par le motif new
la classe list
list.append permet d’ajouter un objet en queue l = [1,2]
de list l.append(20)
l donne [1,2,20,20]
list.copy retourne une copie superficielle de l = [1,2,20]; l1 = l.copy(); print(l1)
la liste. donne [1,2,20]
la classe dict
dict.keys Retourne un itérable formé par les list({1:3,"med":5}.keys())
clés du dict. donne [1,"med"]
dict.values Retourne un itérable formé par les list({1:3,"med":5}.values())
valeurs du dict. donne [3,5]
dict.pop Supprime puis retourne la valeur d = {1:3,"med":5}
associée à la clé passée en para- d.pop(1) donne 3
mètre. d donne {"med":5}
dict.update Mettre à jour le dict en utilisant d = {1:3,"med":5}
les éléments du dict passé en pa- d.update({1:5, "ali":6})
ramètre. d donne {1:5, "med":5, "ali":6}
d[clé] = valeur Insérer /mettre à jour la paire (clé,
valeur)
la classe set
set.add ajoute un élément à l’ensemble s = set()
s.add("med ali")
s donne {"med ali"}
set.discard élimine un élément de l’ensemble s = {"med", "ali"}
s.discard("ali")
s donne {"med"}
Fonction utile sur les itérables
max(it) Retourne la valeur maximale d’un max({5:2, 10:2, -10:22})
itérable it donne 10
Méthodes magiques