Skip to content
Snippets Groups Projects
Commit 0ea6fbe2 authored by paul.albuquer's avatar paul.albuquer
Browse files

added lesson 6, fig. 8-queens, version 2020-21, recursivity codes

parent f0cc8c59
No related branches found
No related tags found
No related merge requests found
Pipeline #14747 passed
# Algorithmique et structures de données 2020-21
Contenu du cours 6 du 28.10.2020
*****
## Récursivité
- Exemple de la factorielle : n ! = n·(n-1)·(n-2)·... ·3·2·1 = n·(n-1) !
Donc fact(n) = n·fact(n-1) (récursivité)
et fact(1) = 1 (condition d'arrêt)
```C
int fact(int n) {
if (n > 1) {
return n*fact(n­1);
} else {
return 1;
}
}
void main() {
int f = fact(4);
}
```
![Illustration](./figures/fig_recursivite_factorielle.png)
- Exemple du PGCD
Algorithme d'Euclide pour le PGCD de 42 et 27
> 42 = 27·1 + 15
> 27 = 15·1 + 12
> 15 = 12·1 + 3
> 12 = 3·4 + 0
PGCD(42,27)=PGCD(27,15)=PGCD(15,12)=PGCD(12,3)=3
```C
int pgcd(int n,int m) {
if (n%m > 0) {
return pgcd(m,n%m);
} else {
return m;
}
}
```
![Illustration de la récursivité pour l'algorithme d'Euclide](./figures/fig_recursivite_pgcd_euclide.png)
- Exemple de l'écriture binaire
```C
void binaire(int n) {
printf("%d",n%2);
if (n/2 != 0) {
binaire(n/2);
} else {
printf("\n");
}
// printf("%d",n%2);
}
Binaire(13); // affiche 1 0 1 1 puis un retour à la ligne`
```
> > > $\hspace*{36mm} 2^0 2^1 2^2 2^3$
![Illustration de la récursivité pour l'écriture binaire](./figures/fig_recursivite_binaire.png)
- Que se passe-t-il si on décommente le deuxième `printf` ?
## Exemples et exercices de récursivité
- Algorithme du PPCM de deux nombres `n` et `m`
- `ppcm(mult_n,mult_m) = ppcm(mult_n + n, mult_m)`
si `mult_n < mult_m` (récursivité)
- `ppcm(mult_n,mult_m) = ppcm(mult_n, mult_m + m)`
si `mult_n > mult_m` (récursivité)
- `ppcm(mult_n,mult_m) = mult_n`
si `mult_n = mult_m` (condition d’arrêt)
- Puissance indienne
\begin{align*}
a^b & = a^{b/2}\cdot a^{b/2} & \textrm{ si $b$ est pair (récursivité)} \\
a^b & = a^{b-1}\cdot a & \textrm{ si $b$ est impair (récursivité)} \\
a^0 & = 1 & \textrm{ (condition d’arrêt)}
\end{align*}
- Suite de Fibonacci
\begin{align*}
a_n & = a_{n-1} + a_{n-2} & \textrm{ (récursivité)} \\
a_1 & = 1, a_0 = 0 & \textrm{ (condition d’arrêt)}
\end{align*}
## Problème des 8-reines
- Le but du problème des 8 reines est de placer 8 reines d'un jeu d'échecs sur un échiquier de $8 \times 8$ cases sans que les reines ne puissent se menacer mutuellement, conformément aux règles du jeu d'échecs.
- Ainsi, deux reines ne devraient jamais partager la même rangée, colonne, ou diagonale.
- Le problème se généralise au placement de N reines sur un échiquier de $N \times N$ cases. Pour $N=8$, il y a 92 solutions
- Il s'agit d'un exemple classique de problème de backtracking qui se programme avec la récursivité.
![Problème des 8-reines. Source : wikipedia, https://fr.wikipedia.org/wiki/Problème_des_huit_dames](./figures/fig_recursivite_8_reines.png)
\ No newline at end of file
lessons/figures/fig_recursivite_8_reines.png

10.9 KiB

#include <stdio.h>
#include <stdlib.h>
const int SIZE = 64;
// Moyenne des pixels de l'image <im>
double moyenne(int n,int im[n][n]) {
double size = n*n;
double moy = 0.0;
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
moy += im[i][j]/size;
}
}
return moy;
}
// Nombre de pixels de l'image <im> dont la différence
// à la valeur <val> est supérieure à une tolérance <tol>
int nb_pixels_diff(int n,int im[n][n],double val,double tol) {
// à compléter
return 0;
}
// Affectation de la valeur <val> à tous les pixels de l’image <im>
void copy(int n,int im[n][n],int val) {
// à compléter
}
void copy_slice(int decal_x,int decal_y,int n,int im1[n][n],int k,int im2[k][k]) {
// à compléter
}
void copy_back(int decal_x,int decal_y,int n,int im1[n][n],int k,int im2[k][k]) {
// à compléter
}
//Lissage récursif de l'image <im> en remplaçant les pixels
// d'un quadrant par leur moyenne
void lissage(int n,int im[n][n],double tol,double seuil) {
double moy = moyenne(n,im);
double size = n*n;
if (nb_pixels_diff(n,im,moy,tol)/size < seuil) {
copy(n,im,moy);
} else { // si on ne peut pas lisser l'image, alors on essaie sur les quadrants
int quadrant[n/2][n/2];
copy_slice(0,0,n,im,n/2,quadrant);
lissage(n/2,quadrant,tol,seuil);
copy_back(0,0,n,im,n/2,quadrant);
copy_slice(n/2,0,n,im,n/2,quadrant);
lissage(n,quadrant,tol,seuil);
copy_back(n/2,0,n,im,n/2,quadrant);
copy_slice(0,n/2,n,im,n/2,quadrant);
lissage(n/2,quadrant,tol,seuil);
copy_back(0,n/2,n,im,n/2,quadrant);
copy_slice(n/2,n/2,n,im,n/2,quadrant);
lissage(n,quadrant,tol,seuil);
copy_back(n/2,n/2,n,im,n/2,quadrant);
}
}
void main() {
int image_gris[SIZE][SIZE];
copy(SIZE,image_gris,234);
lissage(SIZE,image_gris,0.1,10.0);
}
#include <stdio.h>
#include <stdlib.h>
// Ecriture binaire
void binaire(int n);
int main() {
int n;
printf("n=");
scanf("%d",&n);
binaire(n);
printf("\n");
}
// Ecriture binaire
void binaire(int n) {
//printf("%d",n%2);
if (n/2 != 0) {
binaire(n/2);
}
printf("%d",n%2);
}
#include <stdio.h>
#include <stdlib.h>
int fact(int n);
void main() {
int n;
printf("n=");
scanf("%d",&n);
printf("%d\n",fact(n));
}
int fact(int n) {
if (1 == n) {
return 1;
} else {
return n*fact(n-1);
}
}
#include <stdio.h>
#include <stdlib.h>
// Suite de Fibonacci: a_n = a_{n-1} + a_{n-2}, a_0 = 0, a_1 = 1
int fib(int n);
int main() {
int n;
printf("n=");
scanf("%d",&n);
printf("%d\n",fib(n));
}
// Suite de Fibonacci: a_n = a_{n-1} + a_{n-2}, a_0 = 0, a_1 = 1
int fib(int n) {
switch(n) {
case 0: return 0;
case 1: return 1;
default: return fib(n-1)+fib(n-2);
}
}
#include <stdio.h>
#include <stdlib.h>
int pgcd(int n,int m);
void main() {
int n,m;
printf("n=");
scanf("%d",&n);
printf("m=");
scanf("%d",&m);
printf("%d\n",pgcd(n,m));
}
int pgcd(int n,int m) {
if (n%m > 0) {
return pgcd(m,n%m);
} else {
return m;
}
}
#include <stdio.h>
#include <stdlib.h>
int ppcm(int mult_n,int mult_m,int n,int m);
void main() {
int n,m;
printf("n=");
scanf("%d",&n);
printf("m=");
scanf("%d",&m);
printf("%d\n",ppcm(n,m,n,m));
}
int ppcm(int mult_n,int mult_m,int n,int m) {
if (mult_n < mult_m) {
return ppcm(n+mult_n,mult_m,n,m);
} else if (mult_n > mult_m) {
return ppcm(mult_n,m+mult_m,n,m);
} else {
return mult_n;
}
}
#include <stdio.h>
#include <stdlib.h>
// Puissance indienne
int puissance(int a,int b);
int main() {
int n,m;
printf("n=");
scanf("%d",&n);
printf("m=");
scanf("%d",&m);
printf("%d\n",puissance(n,m));
}
// Puissance indienne
int puissance(int a,int b) {
if (0 == b) {
return 1;
} else if (0 == b%2) {
return puissance(a,b/2)*puissance(a,b/2);
} else {
return puissance(a,b-1)*a;
}
}
// Problème des N-reines
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
bool** board_alloc(int n) {
bool** tab = malloc(n*sizeof(bool*));
for (int i=0;i<n;i++) {
tab[i] = malloc(n*sizeof(bool));
for (int j=0;j<n;j++) {
tab[i][j] = true;
}
}
return tab;
}
void board_free(int n,bool** tab) {
for (int i=0;i<n;i++) {
free(tab[i]);
}
free(tab);
}
bool** clone(int n,bool** board) {
bool** tab = board_alloc(n);
for (int i=0;i<n;i++) {
for (int j=0;j<n;j++) {
tab[i][j] = board[i][j];
}
}
return tab;
}
// 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)>
bool** prises_devant(int n,bool** board,int li,int co) {
bool** cases_prises = clone(n,board);
cases_prises[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) {
cases_prises[li-j][co+j] = false;
}
cases_prises[li][co+j] = false;
if (li+j < n) {
cases_prises[li+j][co+j] = false;
}
}
return cases_prises;
}
// Calcule le nombre de solutions au problème des <N> reines
void nb_sol(int n,bool** board,int co, int* ptr_cpt) {
for (int li=0;li<n;li++) {
if (board[li][co]) {
if (co < n-1) {
bool** tab = prises_devant(n,board,li,co);
nb_sol(n,tab,co+1,ptr_cpt);
board_free(n,tab);
} else {
*ptr_cpt = (*ptr_cpt)+1;
}
}
}
}
void main() {
int n = 8;
// échiquier où placer les reines
bool** board = board_alloc(n);
// compteur du nombre de solutions au problème des <N> reines
int cpt = 0;
nb_sol(n,board,0,&cpt);
printf("Nombre de solutions: %d\n",cpt);
}
// Problème des N-reines
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
// Alloue un tableau de dimension nxn de booléens dont le contenu est true
bool** board_alloc(int n) {
// à compléter!!!!
return NULL;
}
// Désalloue un tableau de dimension nxn de booléens
void board_free(int n,bool** tab) {
// à compléter!!!!
}
// Retourne un clone de <board>
bool** clone(int n,bool** board) {
// à compléter!!!!
return NULL;
}
// 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)>
bool** prises_devant(int n,bool** board,int li,int co) {
bool** cases_prises = clone(n,board);
// à compléter!!!!
return cases_prises;
}
// Calcule le nombre de solutions au problème des <N> reines
void nb_sol(int n,bool** board,int co, int* ptr_cpt) {
for (int li=0;li<n;li++) {
if (board[li][co]) {
if (co < n-1) {
bool** tab = prises_devant(n,board,li,co);
nb_sol(n,tab,co+1,ptr_cpt);
board_free(n,tab);
} else {
*ptr_cpt = (*ptr_cpt)+1;
}
}
}
}
void main() {
int n = 8;
// échiquier où placer les reines
bool** board = board_alloc(n);
// compteur du nombre de solutions au problème des <N> reines
int cpt = 0;
nb_sol(n,board,0,&cpt);
printf("Nombre de solutions: %d\n",cpt);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment