Select Git revision
Forked from
algorithmique / cours
549 commits behind the upstream repository.
orestis.malaspin authored
cours_8.md 8.58 KiB
- L'algorithme du PPCM récursif (1/3)
- Exemple d'algorithme pour le calcul
- L'algorithme du PPCM récursif (2/3)
- Rappel de l'algorithme
- Écrire l'algorithme récursif du PPCM (matrix)
- L'algorithme du PPCM récursif (3/3)
- Pseudo-code
- Problème des 8-reines
- Conséquence
- Généralisation
- Problème des 2-reines
- Comment trouver les solutions?
- Problème des 3-reines
- Problème des 4-reines
- Problème des 4-reines, symétrie
- Problème des 5 reines
- Exercice: Trouver une solution au problème des 5 reines
- Quelques observations sur le problème
- Le code du problème des 8 reines (1/N)
- Quelle structure de données?
- Quelles fonctionalités?
- Le code du problème des 8 reines (2/N)
- Le calcul du nombre de solutions
- Le code du problème des 8 reines (3/N)
- Le calcul du nombre de solutions
- Le code du problème des 8 reines (4/N)
- Compris? Alors écrivez le code et postez le!
- Le nombre de solutions
- Le code du problème des 8 reines (5/N)
- Placer devant
- Les piles (1/N)
- Qu'est-ce donc?
- Des exemples de la vraie vie
- Les piles (2/N)
- Fonctionnalités
- Comment faire les 4,5 à partir de 1 à 3?
- Existe en deux goûts
- Les piles (3/N)
- Implémentation
- Quelle structure de données allons nous utiliser?
- La structure: de quoi avons-nous besoin (pile de taille fixe)?
- Les piles (4/N)
- Initialisation
- Est vide?
- Empiler (ajouter un élément au sommet)
- Les piles (5/N)
- Dépiler (enlever l'élément du sommet)
- Jeter un oeil (regarder le sommet)
- Voyez-vous des problèmes potentiels avec cette implémentation?
title: "Backtracking et piles"
date: "2021-11-17"
patat:
eval:
tai:
command: fish
fragment: false
replace: true
ccc:
command: fish
fragment: false
replace: true
images:
backend: auto
L'algorithme du PPCM récursif (1/3)
Exemple d'algorithme pour le calcul
PPCM(36, 90):
36 < 90 // 36 + 36
72 < 90 // 72 + 36
108 > 90 // 90 + 90
108 < 180 // 108 + 36
144 < 180 // 144 + 36
180 = 180 // The End!
. . .
- On incrémente de 36 à gauche et de 90 à droite jusqu'à ce que les deux soient égaux.
L'algorithme du PPCM récursif (2/3)
Rappel de l'algorithme
// on cherche i*m == j*m (i,j aussi petits que possibles)
int ppcm(int m, int n) {
int mult_m = m, mult_n = n;
while (mult_m != mult_n) {
if (mult_m > mult_n) {
mult_n += n;
} else {
mult_m += m;
}
}
return mult_m;
}
. . .
Écrire l'algorithme récursif du PPCM (matrix)
L'algorithme du PPCM récursif (3/3)
Pseudo-code
- Algorithme du PPCM de deux nombres
netm-
ppcm(mult_n,mult_m) = ppcm(mult_n + n, mult_m)
simult_n < mult_m(récursivité) -
ppcm(mult_n,mult_m) = ppcm(mult_n, mult_m + m)
simult_n > mult_m(récursivité) -
ppcm(mult_n,mult_m) = mult_n
simult_n = mult_m(condition d’arrêt)
-
Problème des 8-reines
- Placer 8 reines sur un échiquier de .
- Sans que les reines ne puissent se menacer mutuellement (92 solutions).
Conséquence
- Deux reines ne partagent pas la même rangée, colonne, ou diagonale.
- Donc chaque solution a une reine par colonne ou ligne.
Généralisation
- Placer reines sur un échiquier de.
- Exemple de backtracking (retour en arrière) récursivité.
Problème des 2-reines
Comment trouver les solutions?
- On pose la première reine sur la première case disponible.
- On rend inaccessibles toutes les cases menacées.
- On pose la reine suivante sur la prochaine case non-menacée.
- Jusqu'à ce qu'on puisse plus poser de reine.
- On revient alors en arrière jusqu'au dernier coup où il y avait plus qu'une possibilité de poser une reine.
- On recommence depuis là.
. . .
- Le jeu prend fin quand on a énuméré toutes les possibilités de poser les reines.
Problème des 3-reines
Problème des 4-reines
Problème des 4-reines, symétrie
Problème des 5 reines
Exercice: Trouver une solution au problème des 5 reines
- Faire une capture d'écran / une photo de votre solution et la poster sur matrix.
Quelques observations sur le problème
- Une reine par colonne au plus.
- On place les reines sur des colonnes successives.
- On a pas besoin de "regarder en arrière" (on place "devant" uniquement).
- Trois étapes:
- On place une reine dans une case libre.
- On met à jour le tableau.
- Quand on a plus de cases libres on "revient dans le temps" ou c'est qu'on a réussi.
Le code du problème des 8 reines (1/N)
Quelle structure de données?
. . .
Une matrice de booléens fera l'affaire:
bool board[n][n];
Quelles fonctionalités?
. . .
// Pour chaque ligne placer la reine sur toutes les colonnes
// et compter les solutions
void nbr_solutions(board, column, counter);
// Copier un tableau dans un autre
void copy(board_in, board_out);
// Placer la reine à li, co et rendre inaccessible devant
void placer_devant(board, li, co);
Le code du problème des 8 reines (2/N)
Le calcul du nombre de solutions
// Calcule le nombre de solutions au problème des <n> reines
nbr_solutions(board, column, count)
// pour chaque ligne
// si la case libre
// si column < n - 1
// copier board dans un "new" board,
// y poser une reine
// et mettre à jour ce "new" board
// nbr_solutions(new_board, column+1, count)
// sinon
// on a posé la n-ème et on a gagné
// count += 1
Le code du problème des 8 reines (3/N)
Le calcul du nombre de solutions
// Placer une reine et mettre à jour
placer_devant(board, ligne, colonne)
// board est occupé à ligne/colonne
// toutes les cases des colonnes
// suivantes sont mises à jour
Le code du problème des 8 reines (4/N)
Compris? Alors écrivez le code et postez le!
. . .
Le nombre de solutions
\footnotesize
// Calcule le nombre de solutions au problème des <n> reines
void nb_sol(int n, bool board[n][n], int co, int *ptr_cpt) {
for (int li = 0; li < n; li++) {
if (board[li][co]) {
if (co < n-1) {
bool new_board[n][n]; // alloué à chaque nouvelle tentative
copy(n, board, new_board);
prises_devant(n, new_board, li, co);
nb_sol(n, new_board, co+1, ptr_cpt);
} else {
*ptr_cpt = (*ptr_cpt)+1;
}
}
}
}
Le code du problème des 8 reines (5/N)
\footnotesize
Placer devant
// Retourne une copie du tableau <board> complété avec les positions
// prises sur la droite droite par une reine placée en <board(li,co)>
void prises_devant(int n, bool board[n][n], int li, int co) {
board[li][co] = false; // position de la reine
for (int j = 1; j < n-co; j++) {
// horizontale et diagonales à droite de la reine
if (j <= li) {
board[li-j][co+j] = false;
}
board[li][co+j] = false;
if (li+j < n) {
board[li+j][co+j] = false;
}
}
}
Les piles (1/N)
Qu'est-ce donc?
- Structure de données abstraite...
. . .
- de type
LIFO(Last in first out).
Des exemples de la vraie vie
. . .
- Pile d'assiettes, de livres, ...
- Adresses visitées par un navigateur web.
- Les calculatrices du passé (en polonaise inverse).
- Les boutons undo de vos éditeurs de texte (aka u dans vim).
Les piles (2/N)
Fonctionnalités
. . .
- Empiler (push): ajouter un élément sur la pile.
- Dépiler (pop): retirer l'élément du sommet de la pile et le retrouner.
- Liste vide? (is_empty?).
. . .
- Jeter un oeil (peek): retourner l'élément du sommet de la pile (sans le dépiler).
- Nombre d'éléments (length).
Comment faire les 4,5 à partir de 1 à 3?
. . .
- Dépiler l'élément, le copier, puis l'empiler à nouveau.
- Dépiler jusqu'à ce que la pile soit vide, puis empiler à nouveau.
. . .
Existe en deux goûts
- Pile avec ou sans limite de capacité (à concurrence de la taille de la mémoire).
Les piles (3/N)
Implémentation
- Jusqu'ici on n'a pas du tout parlé d'implémentation (d'où le nom de structure abstraite).
- Pas de choix unique d'implémentation.
Quelle structure de données allons nous utiliser?
. . .
Et oui vous avez deviné: un tableau!
La structure: de quoi avons-nous besoin (pile de taille fixe)?
. . .
#define MAX_CAPACITY 500
typedef struct _stack {
int data[MAX_CAPACITY]; // les données
int top; // indice du sommet
} stack;
Les piles (4/N)
Initialisation
. . .
void stack_init(stack *s) {
s->top = -1;
}
Est vide?
. . .
bool stack_is_empty(stack s) {
return s.top == -1;
}
Empiler (ajouter un élément au sommet)
. . .
void stack_push(stack *s, int val) {
s->top += 1;
s->data[s->top] = val;
}
Les piles (5/N)
Dépiler (enlever l'élément du sommet)
. . .
int stack_pop(stack *s) {
s->top -= 1;
return s->data[s->top+1];
}
Jeter un oeil (regarder le sommet)
. . .
int stack_peek(stack *s) {
return s->data[s->top];
}
Voyez-vous des problèmes potentiels avec cette implémentation?
. . .
- Empiler avec une pile pleine.
- Dépiler avec une pile vide.
- Jeter un oeil au sommet d'une pile vide.
