• Aucun résultat trouvé

Représentation des permutations

Algorithmique et programmation

1.2 Représentation des permutations

Pour générer les permutations en utilisant cette observation, Johnson représente une permutation par des entiers munis d’une girouette : on associe à chaque entier une flèche

indiquant une direction.

exemple :

⃖ ⃖ ⃖ ⃖

Définitions :

Lorsque la girouette d’un entier x est orientée vers un autre entier y, on dit que x

regarde y. Dans l’exemple précédent :

o regarde o regarde o regarde

o regarde o regarde

Lorsqu’un entier x est situé tout à gauche (respectivement tout à droite) et que sa girouette indique la gauche (respectivement la droite), on dit que x regarde dehors. Dans l’exemple précédent, et regardent dehors.

On dit qu’un entier est mobile s’il ne regarde pas dehors et s’il regarde un entier plus petit que lui. Dans l’exemple, seuls les entiers , , et sont mobiles.

algorithme de Johnson

1.3 Algorithme

L’algorithme de Johnson génère toute les permutations de { } de la manière suivante :

 On commence avec la permutation ⃖ ⃖ ⃖ ⃖ ⃖ ⃖ .

 On répète le traitement suivant :

 On affiche la permutation courante.

On recherche le plus grand entier mobile (PGEM) m.

 Si on trouve un entier mobile :

 On échange et l’entier que regarde, sans changer le sens de leurs girouettes respectives.

 On inverse le sens des girouettes de tous les entiers .  On recommence.

 Si on ne trouve pas d’entier mobile, l’algorithme se termine.

2 Implémentation

Exercice 1

En utilisant l’algorithme de Johnson, vérifiez à la main que l’on obtient bien les permutations de { }, comme décrit précédemment.

Exercice 2

Définissez un type énuméré t_girouette, permettant de décrire l’orientation d’une girouette. Définissez un type structure t_entier_girouette permettant de représenter un entier et sa girouette.

Exercice 3

Une permutation sera représentée par un tableau de valeurs de type

t_entier_girouette. Écrivez une fonction initialise_permutation qui effectue l’initialisation (1er

point de l’algorithme) de ce tableau, qui sera passé à la fonction en paramètre.

Remarque : notez que la taille de la permutation est ici variable (à la différence du TP sur la décomposition de permutations, où on utilise une constante ). Cette taille doit donc être passée en paramètre.

exemple : pour une taille , la fonction doit renvoyer la permutation ⃖ ⃖ ⃖ ⃖ ⃖ ⃖ ⃖ .

Exercice 4

Écrivez une fonction affiche_permutation qui affiche une permutation passée en paramètre (3ème point de l’algorithme).

exemple : pour la permutation ⃖ ⃖ ⃖ ⃖ , on affichera : <- <- <- -> <- -> ->

0 2 4 6 5 3 1

Exercice 5

Écrivez une fonction identifie_pgem qui calcule la valeur et la position du plus grand entier mobile de la permutation passée en paramètre (4ème point de l’algorithme).

exemple : pour la permutation ⃖ ⃖ ⃖ ⃖ , la fonction doit renvoyer la position , qui correspond à .

algorithme de Johnson

Écrivez une fonction deplace_entier qui reçoit en paramètres (au moins) une permutation et la position d’un entier dans cette permutation. On suppose que la position reçue correspond à un entier mobile. La fonction doit échanger l’entier situé à cette position, avec l’entier qu’il regarde (6ème

point de l’algorithme).

exemples : pour la permutation ⃖ ⃖ ⃖ ⃖

 Si on spécifie la position , on obtient ⃖ ⃖ ⃖ ⃖ .

 Si on spécifie la position , on obtient ⃖ ⃖ ⃖ ⃖ .

Exercice 7

Écrivez une fonction inverse_girouette qui inverse, dans une permutation, les girouettes de tous les entiers strictement supérieurs à un entier (7ème

point de l’algorithme). La permutation et doivent être passés en paramètres.

exemple : pour la permutation ⃖ ⃖ ⃖ ⃖ et , on obtient ⃖ ⃖ ⃖ ⃖ .

Exercice 8

Écrivez une fonction johnson qui prend en paramètre un entier n et affiche toutes les permutations de { } en utilisant l’algorithme de Johnson.

exemple : pour , on obtient l’affichage suivant (similaire à celui du début du sujet) : <- <- <- <- 0 1 2 3 <- <- <- <- 0 1 3 2 <- <- <- <- 0 3 1 2 <- <- <- <- 3 0 1 2 -> <- <- <- 3 0 2 1 <- -> <- <- 0 3 2 1 <- <- -> <- 0 2 3 1 <- <- <- -> 0 2 1 3 <- <- <- <- 2 0 1 3 <- <- <- <- 2 0 3 1 <- <- <- <- 2 3 0 1 <- <- <- <- 3 2 0 1 -> -> <- <- 3 2 1 0 -> -> <- <- 2 3 1 0 -> <- -> <- 2 1 3 0 -> <- <- -> 2 1 0 3 <- -> <- <- 1 2 0 3 <- -> <- <- 1 2 3 0 <- <- -> <- 1 3 2 0 <- <- -> <- 3 1 2 0 -> <- <- -> 3 1 0 2 <- -> <- -> 1 3 0 2 <- <- -> -> 1 0 3 2 <- <- -> -> 1 0 2 3

Université Galatasaray

Faculté d’ingénierie et de technologie – Génie informatique

Algorithmique et programmation

Damien Berthet & Vincent Labatut

TP 20

manipulation de dates

Présentation

Dans ce TP, on veut créer une bibliothèque date permettant de représenter et de manipuler des dates, en définissant nos propres types structure et énuméré. Cette bibliothèque sera ensuite utilisée dans d’autres TP.

1 Représentation des mois

Exercice 1

Créez un projet et les fichiers nécessaires : date.c, date.h et main.c. Initialisez ces fichiers de façon appropriée (cf. les TP précédents portant sur la définition de bibliothèque).

Exercice 2

On veut représenter les mois avec un type énuméré (et non pas avec un entier). Ce type doit contenir les symboles suivants : jan, fev, mars, avr, mai, juin, juil, aout, sept, oct, nov et dec. De plus, on veut que chaque mois soit associé à la valeur numérique appropriée : jan à , fev à , etc.

Dans date.h, définissez un type énuméré t_mois respectant ces contraintes.

Remarque : les types contenus dans une bibliothèque xxxx doivent toujours être définis dans le fichier d’en-tête xxxx.h.

Exercice 3

Dans date, écrivez la fonction void affiche_mois(t_mois m) qui affiche le texte complet correspondant au mois passé en paramètre.

exemples :

affiche_mois(jan) doit afficher "janvier" ;

affiche_mois(fev) doit afficher "fevrier" ;

 etc.

Contrainte : vous n’avez pas le droit d’utiliser if dans cette fonction.

2 Représentation des dates

Exercice 4

Dans date.h, Définissez un type structure t_date permettant de représenter une date décomposée en jour, mois et année, comme par exemple : 20 novembre 2011. Le jour et l’année sont des entiers naturels, alors que le mois est de type mois.

Exercice 5

manipulation de dates

20 novembre 2011

Exercice 6

Dans date, écrivez une fonction saisis_date qui permet à l’utilisateur de saisir une date, et qui la renvoie par valeur.

exemple : saisie de la date donnée dans l’exemple précédent

Entrez le jour : 20 Entrez le mois : 11 Entrez l’année : 2006

Remarque : n’oubliez pas que les valeurs des types énumérés sont en réalité représentées

sous la forme d’entiers.

Exercice 7

Dans date, écrivez une fonction int compare_dates(t_date date1, t_date date2) qui compare les deux dates passées en paramètres et renvoie un entier :

 Négatif si date1 est antérieure à date2 ;

 Zéro si date1 et date2 sont exactement les mêmes ;

 Positif si date1 est postérieure à date2.

exemples :

 Pour les dates 01/01/2014 et 01/02/2014, la fonction renvoie (ou autre valeur négative) ;

 Pour les dates 01/01/2014 et 01/01/2014, la fonction renvoie ;

 Pour les dates 01/01/2014 et 01/02/2013, la fonction renvoie (ou autre valeur positive).

Exercice 8

Dans date, écrivez une fonction copie_date qui reçoit en paramètre une date (i.e. une valeur de type t_date) et crée une nouvelle valeur de type t_date qui est la copie de cette date. À vous de décider si la copie doit être passée par adresse ou par valeur.

Remarque : il s’agit bien de créer une nouvelle valeur, et non pas de faire pointer deux

pointeurs différents sur la même valeur en mémoire.

3 Calculs sur les années

Exercice 9

Dans date, écrivez une fonction int est_bissextile(int annee) qui prend une année en paramètre et renvoie si elle est bissextile, et sinon. D’après Wikipedia, une année est bissextile ssi :

 Soit elle est divisible par mais pas par ;

 Soit elle est divisible par .

exemples : et sont bissextiles, et ne sont pas bissextiles.

Exercice 10

Dans date, écrivez une fonction int indique_jours(int annee, t_mois mois) qui reçoit en paramètre une année et un mois, et renvoie le nombre de jours composant ce mois lors de cette année-là. Pensez à utiliser la fonction précédente.

Contrainte : vous ne pouvez utiliser qu’un seul if dans cette fonction.

Exercice 11

manipulation de dates

On veut améliorer la fonction saisis_date, de manière à s’assurer que les valeurs reçues sont bien valides. Dans date, écrivez une fonction saisis_date_verif qui effectue les tests suivants lors de la saisie de la date par l’utilisateur :

 L’année doit être un entier compris entre et (inclus) ;

 Le mois doit être un entier entre et (inclus) ;

 Le jour doit être un entier entre et le nombre de jours contenus dans ce mois pour cette année-là.

Pour chacune de ces trois données, le programme doit demander à l’utilisateur d’entrer une valeur, en recommençant tant que la valeur n’est pas conforme à ces contraintes.

exemple :

Entrez l'annee (1900<=entier<=2011) : 2000 Entrez le mois (1<=entier<=12) : 13

Entrez le mois (1<=entier<=12) : 2 Entrez le jour (1<=entier<=29) : 30 Entrez le jour (1<=entier<=29) : 29

4 Calculs divers

Exercice 12

Dans date, écrivez une fonction void ajoute_jour(t_date* date) qui ajoute un jour à la date passée en paramètre. Attention, votre fonction doit tenir compte du mois et aussi de l’année (qui peut être bissextile).

exemples :

 Pour la date 01/01/2014, la fonction doit renvoyer 02/01/2014.

 Pour la date 31/01/2014, la fonction doit renvoyer 01/02/2014.

 Pour la date 28/02/2014, la fonction doit renvoyer 01/03/2014.

 Pour la date 28/02/2012, la fonction doit renvoyer 29/02/2012.

Exercice 13

Dans date, écrivez une fonction int calcule_duree(t_date date1, t_date date2) qui calcule le nombre de jours entre les deux dates passées en paramètres. Notez qu’il est possible d’obtenir une valeur négative, si date1 n’est pas antérieure à date2.

Pour cela, vous devez implémenter l’algorithme suivant :

 Identifiez la date la plus petite, et en faire une copie.

 Tant qu’on n’a pas atteint la date la plus grande, on incrémente simultanément : o La date la plus petite ;

o Une variable entière utilisée pour compter les jours.

Vous avez besoin des fonctions compare_dates, copie_date, et ajoute_jour.

exemples :

 Pour les dates 01/01/2014 et 12/02/2014, la fonction doit renvoyer .

 Pour les dates 10/01/2014 et 5/01/2014, la fonction doit renvoyer .

 Pour les dates 31/12/2013 et 01/01/2014, la fonction doit renvoyer .

 Pour les dates 26/02/2014 et 05/03/2015, la fonction doit renvoyer .

 Pour les dates 26/02/2012 et 05/03/2013, la fonction doit renvoyer .

Remarque : l’algorithme donné ici n’est pas forcément très efficaces du point de vue de

la rapidité du calcul, mais il a l’avantage d’être simple à implémenter.

Exercice 14

manipulation de dates

Dans le fichier main.c, écrivez une fonction void saisis_recettes(int recettes[])

qui reçoit en paramètre un tableau vide suffisamment grand, et qui demande à l’utilisateur de saisir la recette de chaque mois.

Contrainte : aucune variable entière ne doit être utilisée dans cette fonction (à part le

tableau recettes).

exemple :

Entrez la recette du mois de janvier : 1534 Entrez la recette du mois de fevrier : 12351 Entrez la recette du mois de mars : 5621 ...

Université Galatasaray

Faculté d’ingénierie et de technologie – Génie informatique

Algorithmique et programmation

Damien Berthet & Vincent Labatut

TP 21

carrés latins

Présentation

Le but de ce TP est d’approfondir les tableaux en manipulant des matrices d’entiers particulières, appelée carrés latins. On aura pour cela recours à la notion de type énuméré, déjà abordée dans des TP précédents.

1 Définition

Un carré latin d’ordre est une matrice d’entiers compris entre et , et tel que chaque ligne et chaque colonne contient tous les entiers de à .

exemple : carré latin d’ordre : [ ]

On notera les éléments ( ) d’un carré latin .

Exercice 1

Cherchez manuellement un carré latin d’ordre , et un autre d’ordre .

Exercice 2

Écrivez une fonction void affiche_cl(int m[N][N]) qui affiche un carré latin m d’ordre N. La constante N doit être préalablement déclarée, avec la valeur que vous voulez.

exemple : pour le carré latin de l’exemple précédent, on obtient :

0 1 2 3 0 0 3 2 2 3 0 1 3 2 1 0

Exercice 3

Pour tout entier , on peut construire un carré latin d’ordre par permutation circulaire :

[

]

Écrivez une fonction void genere_cl_permutation(int m[N][N]) qui prend en argument une matrice d’ordre N, et qui initialise cette matrice pour obtenir un carré latin en utilisant le principe décrit ci-dessus.

carrés latins

exemple : pour N=10, on obtient la matrice suivante : 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 0 1 3 4 5 6 7 8 9 0 1 2 4 5 6 7 8 9 0 1 2 3 5 6 7 8 9 0 1 2 3 4 6 7 8 9 0 1 2 3 4 5 7 8 9 0 1 2 3 4 5 6 8 9 0 1 2 3 4 5 6 7 9 0 1 2 3 4 5 6 7 8

Documents relatifs