Dans ce travail pratique, on reprend le contexte du TP2, où un agent explore un univers constitué de salles liées par des portails, avec quelques ajouts :
On voudrait cette fois trouver le chemin le plus rapide (le plus court en temps) pour se rendre d'une cellule à une autre.
Comme nous l'avons vu, le nombre de chemins possibles peut être très grand, même dans un univers assez petit,
donc calculer les longueurs de tous les chemins n'est pas une bonne option en terme d'efficacité.
Par conséquent, plutôt que de tous les explorer, on peut représenter l'univers sous forme d'un graphe
et utiliser un algorithme de calcul de plus court chemin.
En outre, comme il existe souvent plusieurs plus courts chemins entre deux cellules, on aimerait connaître
le nombre de plus courts chemins. Pour le trouver, on peut adapter l'algorithme proposé au TP2.
Par défaut, les déplacements unitaires possibles sont les mêmes que dans le TP2, donc à l'horizontale, à la verticale, et via les portails. Au départ, l'agent n'a pas de diagonaliseur sur lui. Quand il passe sur une cellule qui en contient un, il peut le ramasser et le garder avec lui jusqu'à destination. Avoir un diagonaliseur permet de se déplacer en diagonale, en plus des autres déplacements possibles. Par exemple, si l'agent a un diagonaliseur, à partir de la position (1,2) il peut se rendre directement (en un déplacement unitaire) aux positions suivantes : (0,1), (0,2), (0,3), (1,1), (1,3), (2,1), (2,2) et (2,3), sous réserve bien sûr que ces positions soient valides dans la salle courante. Chaque déplacement prend un certain temps :
Même si ramasser un diagonaliseur prend du temps et peut nécessiter un détour, cela peut être avantageux. On peut l'illustrer par un exemple. La figure 1 montre un plus court chemin de la position (3,0) dans la salle 0 (cellule S) à la position (2,3) dans la salle 2 (cellule E), en l'absence de diagonaliseur. Le déplacement total se fait en 13 unités de temps (7 flèches à 1 unité + 2 portails à 3 unités chacun).
Comme les voisins d'une cellule ne sont pas les mêmes selon que l'agent possède un diagonaliseur ou non, une astuce consiste à "dédoubler" l'univers : on a deux sommets pour chaque cellule. En d'autres termes, un état de l'agent est caractérisé par sa position ainsi que le fait de posséder ou non un diagonaliseur. Le lien entre les deux copies de l'univers se fait comme suit
L'algorithme de Dijkstra permet de calculer un seul plus court chemin entre deux sommets donnés, alors qu'une requête nbPlusCourts
doit trouver tous les plus courts chemins et retourner leur nombre.
L'algorithme du TP2 explore toutes les possibilités de chemins possibles, et incrémente un compteur chaque fois qu'on
trouve un chemin.
Pour trouver tous les plus courts chemins, on peut exploiter l'algorithme de Dijkstra et adapter l'algorithme du TP2
en utilisant la stratégie suivante (de "séparation et évaluation progressive", ou branch and bound) :
Pour bien amorcer ce travail, il est fortement recommandé de commencer avec le squelette de départ fourni dans tp5.zip. Vous pouvez modifier ces fichiers autant que vous le désirez. Toutefois, pour la correction automatique, vous devez préserver la syntaxe d'appel du programme et ses formats d'entrée et de sortie.
Le programme tp5 doit pouvoir être lancé en ligne de commande avec la syntaxe suivante.
./tp5 -c univers.txt [graphe.txt] ./tp5 graphe.txt [requetes.txt]où :
graphe.txt
s'il est donné comme argument,
sinon dans le terminal (sortie standard). Cet aspect est déjà implémenté.
Un fichier d'univers contient une liste de salles, suivie d'une liste de portails, puis d'une liste de diagonaliseurs. Chaque cellule suit la même syntaxe qu'au TP2. Par exemple, le fichier figure2-univers.txt ci-bas décrit l'univers de l'exemple de la Figure 2.
carre 4 diamant 5 triangle 7 ----- 0 (1,0) <--> 1 (0,2) 0 (0,3) <--> 2 (0,6) 1 (3,3) <--> 2 (3,3) ----- 0 (2,1)
Les contraintes sur les numéros de salles restent les mêmes qu'au TP2.
Un fichier de graphe contient une liste de sommets, suivie d'une liste d'arcs :
0 : 0 (0,0) - 1 : 0 (0,1) - ... n : 0 (0,0) D n+1 : 0 (0,1) D ... ----- 0 1 : 1 0 2 : 1 ...Pour chaque sommet, son identifiant est suivi de
":"
puis de l'état correspondant, c'est-à-dire
la cellule et un caractère 'D'
ou '-'
selon que l'on possède un diagonaliseur ou non.
Les identifiants des sommets sont les entiers successifs de 0 à 2n-1, où n est le nombre de cellules dans l'univers.
Pour chaque arête, on a les deux identifiants de noeuds séparés par un espace (départ puis arrivée de l'arête),
puis ":"
et le temps du déplacement unitaire correspondant.
Les fichiers mini-univers.txt et mini-graphe.txt montrent
un exemple d'univers avec le graphe à générer.
Important : pour des fins de correction, il faut
Il y a deux types de requêtes, avec la même syntaxe : nom_requete ":" S ">" E
, où S et E sont les cellules
de départ et d'arrivée (comme dans les figures ci-dessus). Exemple :
plusCourt : 0 (3,0) > 2 (2,3) nbPlusCourts : 0 (3,0) > 2 (2,3)
"plusCourt"
doit trouver un plus court chemin de S à E, et afficher le temps total
suivi de ":"
puis la liste des états constituant le chemin, séparés par "->"
"nbPlusCourts"
doit afficher le nombre de plus courts chemins de S à EPar exemple, pour l'univers de la Figure 1 (sans diagonaliseur), les deux requêtes ci-dessus affichent :
13 : 0 (3,0) - -> 0 (2,0) - -> 0 (1,0) - -> 1 (0,2) - -> 1 (1,2) - -> 1 (2,2) - -> 1 (2,3) - -> 1 (3,3) - -> 2 (3,3) - -> 2 (2,3) - 3Et pour l'univers de la Figure 2 (avec diagonaliseur) on obtient :
12 : 0 (3,0) - -> 0 (2,0) - -> 0 (2,1) - -> 0 (2,1) D -> 0 (1,2) D -> 0 (0,3) D -> 2 (0,6) D -> 2 (1,5) D -> 2 (2,4) D -> 2 (2,3) D 6S'il n'y a pas de chemin, on affiche
-1 : S
, où S
est la cellule de départ.
Contrairement aux précédents TPs, vous devez maintenant utiliser
les conteneurs de la Bibliothèque standard de C++ (Standard Template Library):
stack
, list
, vector
, priority_queue
, set
, map
, etc.
Cette contrainte vise à mettre en pratique l'utilisation d'une bibliothèque normalisée.
Évidemment, vous pouvez créer vos propres structures lorsque cela est justifié.
Par exemple, si vous avez besoin d'un monceau de base, vous devriez normalement utiliser std::priority_queue
.
Par contre, si vous avez besoin d'une fonctionnalité non offerte dans std::priority_queue
,
comme l'opération «réduire clé», vous pouvez créer et utiliser votre propre classe Monceau
.
Ces cas doivent être brièvement justifiés dans le code source.
Relisez les Politiques et les directives sur les outils informatiques dans le cours INF3105. Votre TP5 doit pouvoir être compilé avec g++ version 11 ou 13 (versions installées sur le serveur java.labunix.uqam.ca).
Des tests sont disponibles dans tests.zip.
Pour lancer les tests, lancez le script evaluer.py
sur une machine Linux.
Vous pouvez par exemple vous connecter sur le serveur java :
ssh codeMS@java.labunix.uqam.caQue vous soyez sur java ou votre propre machine Linux, suivez les instructions suivantes :
cd tp5 wget http://cria2.uqam.ca/INF3105/tp5/tests.zip // si vous n'avez pas encore récupéré le fichier zip make unzip tests.zip cd tests g++ -O3 -o valideur valideur.cpp cd .. ./tests/evaluer.pyVoici un exemple de résultat d'exécution (sur java) :
Évaluation du programme tp5 d'INF3105 Mode: Mode.etudiant Système d'exploitation: Linux CPU: Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz Nom_test CPU Mém PCC TempsOK ChemOK nbPCC nbPCCOK C1a-req10 0.01 4316 10 10 10 10 10 C1a-req100 0.05 4392 100 100 100 100 100 C1a-req1000 0.51 4232 1000 1000 1000 1000 1000 C1b-req10 0.01 4196 10 10 10 10 10 C1b-req100 0.04 4252 100 100 100 100 100 C1b-req1000 0.43 4316 1000 1000 1000 1000 1000 C1c-req10 0.01 4364 10 10 10 10 10 C1c-req100 0.07 4468 100 100 100 100 100 C1c-req1000 0.66 4396 1000 1000 1000 1000 1000 C1d-req10 0.00 4132 10 10 10 10 10 C1d-req100 0.03 4268 100 100 100 100 100 C1d-req1000 0.32 4120 1000 1000 1000 1000 1000 C1e-req10 0.05 8544 10 10 10 10 10 C1e-req100 0.29 8476 100 100 100 100 100 C1e-req1000 2.66 8372 1000 1000 1000 1000 1000 C2a-req10 0.01 4400 10 10 10 10 10 C2a-req100 0.08 4532 100 100 100 100 100 C2a-req1000 0.71 4484 1000 1000 1000 1000 1000 C2b-req10 0.01 4584 10 10 10 10 10 C2b-req100 0.09 4588 100 100 100 100 100 C2b-req1000 0.92 4632 1000 1000 1000 1000 1000 C2c-req10 0.00 4268 10 10 10 10 10 C2c-req100 0.06 4308 100 100 100 100 100 C2c-req1000 0.65 4208 1000 1000 1000 1000 1000 C2d-req10 0.01 4072 10 10 10 10 10 C2d-req100 0.05 4152 100 100 100 100 100 C2d-req1000 0.56 4168 1000 1000 1000 1000 1000 C2e-req10 0.06 7360 10 10 10 10 10 C2e-req100 0.43 7732 100 100 100 100 100 C2e-req1000 4.47 7684 1000 1000 1000 1000 1000 E1b-req10 0.56 64300 10 10 10 0 0 E1b-req100 2.70 64228 100 100 100 0 0 E1b-req1000 24.01 64668 1000 1000 1000 0 0 E2a-req10 0.75 53692 10 10 10 0 0 E2a-req100 4.88 53940 100 100 100 0 0 E2a-req1000 48.03 54104 1000 1000 1000 0 0 G1a-req10 0.25 10044 0 0 0 10 10 G1a-req100 1.61 10328 0 0 0 100 100 G1a-req1000 19.30 10264 0 0 0 1000 1000 G1b-req10 0.36 40588 0 0 0 10 10 G1b-req100 30.65 40852 0 0 0 100 100 G1b-req1000 384.36 40940 0 0 0 1000 1000 G2a-req10 15.87 46604 0 0 0 10 10 G2a-req100 524.07 46944 0 0 0 100 100
Notez que ces temps ont été obtenus à partir d'une implémentation non optimisée. La meilleure solution (parmi les vôtres) servira de référence.
Signification des colonnes:
plusCourt
dans le fichier.plusCourt
pour lesquelles le temps du plus court chemin est correct.plusCourt
qui affichent correctement un plus court chemin.nbPlusCourts
dans le fichier.nbPlusCourts
qui comptent correctement le nombre de plus courts chemins.Vous devez remettre votre travail au plus tard le 13 août 2024 à 23h59m EST (heure de Montréal) via le formulaire de remise du TP5.
Vous pouvez soumettre votre TP autant de fois que vous voulez. Seule la dernière soumission sera considérée.
Ce travail pratique compte pour 10% de la note finale.
Critère | Description | Points |
---|---|---|
A. | Respect des directives pour la remise.
|
10 |
B. | Conversion en graphe Le programme produit le bon fichier graphe.txt quand on lui donne en entrée un fichier univers.txt à convertir. |
20 |
C. | Fonctionnement correct du calcul de chemins Le programme retourne les bons résultats avec la requête plusCourt quand on lui donne en entrée
un fichier de graphe correct
|
45 |
D. | Fonctionnement correct du calcul du nombre de plus courts chemins Le programme retourne les bons résultats avec la requête nbPlusCourts .
|
15 |
E. | Efficacité Temps raisonnables pour calculer des requêtes plusCourt et nbPlusCourts .
|
10 |
Total | 100 |