diff --git a/lessons/contenu_cours_6.md b/lessons/contenu_cours_6.md new file mode 100644 index 0000000000000000000000000000000000000000..0f59c42485a554a844b662b1c01165cf53773a06 --- /dev/null +++ b/lessons/contenu_cours_6.md @@ -0,0 +1,97 @@ +# 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(n1); + } else { + return 1; + } + } + void main() { + int f = fact(4); + } +``` + + + +- 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; + } + } +``` + + + +- 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$ + + + +- 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é. + + \ No newline at end of file diff --git a/lessons/figures/fig_recursivite_8_reines.png b/lessons/figures/fig_recursivite_8_reines.png new file mode 100644 index 0000000000000000000000000000000000000000..7bbe986203f74f1c90fc9a87e86ad796e5d1894d Binary files /dev/null and b/lessons/figures/fig_recursivite_8_reines.png differ diff --git a/source_codes/recursivity/lissage.c b/source_codes/recursivity/lissage.c new file mode 100644 index 0000000000000000000000000000000000000000..f501ca0341730d59fe004543c47f90afb80d8207 --- /dev/null +++ b/source_codes/recursivity/lissage.c @@ -0,0 +1,66 @@ +#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); +} diff --git a/source_codes/recursivity/rec_binary.c b/source_codes/recursivity/rec_binary.c new file mode 100644 index 0000000000000000000000000000000000000000..2eb856bc4f05b1c0bea24aaaef48e56e36f267a6 --- /dev/null +++ b/source_codes/recursivity/rec_binary.c @@ -0,0 +1,23 @@ +#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); +} + diff --git a/source_codes/recursivity/rec_factorielle.c b/source_codes/recursivity/rec_factorielle.c new file mode 100644 index 0000000000000000000000000000000000000000..e5513d194e5d94d2df91b3bce458abee7cc60dd6 --- /dev/null +++ b/source_codes/recursivity/rec_factorielle.c @@ -0,0 +1,19 @@ +#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); + } +} diff --git a/source_codes/recursivity/rec_fibonacci.c b/source_codes/recursivity/rec_fibonacci.c new file mode 100644 index 0000000000000000000000000000000000000000..0c8a4874704743ccf94af3801892bf6db08cd652 --- /dev/null +++ b/source_codes/recursivity/rec_fibonacci.c @@ -0,0 +1,22 @@ +#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); + } +} + diff --git a/source_codes/recursivity/rec_pgcd.c b/source_codes/recursivity/rec_pgcd.c new file mode 100644 index 0000000000000000000000000000000000000000..4c6b6a461b00f5808a4988b62666272d090e5214 --- /dev/null +++ b/source_codes/recursivity/rec_pgcd.c @@ -0,0 +1,23 @@ +#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; + } +} + + diff --git a/source_codes/recursivity/rec_ppcm.c b/source_codes/recursivity/rec_ppcm.c new file mode 100644 index 0000000000000000000000000000000000000000..ef505ee8dc07c860ff36c6b5ed39cc0a1dbe6d2e --- /dev/null +++ b/source_codes/recursivity/rec_ppcm.c @@ -0,0 +1,24 @@ +#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; + } +} + diff --git a/source_codes/recursivity/rec_puissance_indienne.c b/source_codes/recursivity/rec_puissance_indienne.c new file mode 100644 index 0000000000000000000000000000000000000000..ceff6baa53792fd8564aa903449faf8304eca7b5 --- /dev/null +++ b/source_codes/recursivity/rec_puissance_indienne.c @@ -0,0 +1,26 @@ +#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; + } +} + diff --git a/source_codes/recursivity/rec_reines.c b/source_codes/recursivity/rec_reines.c new file mode 100644 index 0000000000000000000000000000000000000000..5f5408874daeb48ab1749df2e4811311ee503e31 --- /dev/null +++ b/source_codes/recursivity/rec_reines.c @@ -0,0 +1,75 @@ +// 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); +} diff --git a/source_codes/recursivity/rec_reines_skel.c b/source_codes/recursivity/rec_reines_skel.c new file mode 100644 index 0000000000000000000000000000000000000000..7b2b056fecd56a80ffef3d3ece094d5105f26347 --- /dev/null +++ b/source_codes/recursivity/rec_reines_skel.c @@ -0,0 +1,54 @@ +// 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); +}