X2012 INF421 Examen de rattrapage / 25 novembre 2013. 1 Le compte est bon



Documents pareils
Recherche dans un tableau

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Java Licence Professionnelle Cours 7 : Classes et méthodes abstraites

chapitre 4 Nombres de Catalan

I. Introduction aux fonctions : les fonctions standards

Pour signifier qu'une classe fille hérite d'une classe mère, on utilise le mot clé extends class fille extends mère

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

Licence Bio Informatique Année Premiers pas. Exercice 1 Hello World parce qu il faut bien commencer par quelque chose...

Définitions. Numéro à préciser. (Durée : )

Utilisation d objets : String et ArrayList

UEO11 COURS/TD 1. nombres entiers et réels codés en mémoire centrale. Caractères alphabétiques et caractères spéciaux.

Prénom : Matricule : Sigle et titre du cours Groupe Trimestre INF1101 Algorithmes et structures de données Tous H2004. Loc Jeudi 29/4/2004

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

Suivant les langages de programmation, modules plus avancés : modules imbriqués modules paramétrés par des modules (foncteurs)

Algorithmes d'apprentissage

Chapitre 10. Les interfaces Comparable et Comparator 1

Polymorphisme, la classe Object, les package et la visibilité en Java... 1

Initiation à la programmation en Python

1 Recherche en table par balayage

Exercices sur les interfaces

MISE A NIVEAU INFORMATIQUE LANGAGE C - EXEMPLES DE PROGRAMMES. Université Paris Dauphine IUP Génie Mathématique et Informatique 2 ème année

Les structures de données. Rajae El Ouazzani

TD3: tableaux avancées, première classe et chaînes

Langage Java. Classe de première SI

Encapsulation. L'encapsulation consiste à rendre les membres d'un objet plus ou moins visibles pour les autres objets.

Représentation d un entier en base b

Ordonnancement. N: nains de jardin. X: peinture extérieure. E: électricité T: toit. M: murs. F: fondations CHAPTER 1

Centre CPGE TSI - Safi 2010/2011. Algorithmique et programmation :

INF2015 Développement de logiciels dans un environnement Agile. Examen intra 20 février :30 à 20:30

INTRODUCTION A JAVA. Fichier en langage machine Exécutable

6. Hachage. Accès aux données d'une table avec un temps constant Utilisation d'une fonction pour le calcul d'adresses

Tp 1 correction. Structures de données (IF2)

Projet d informatique M1BI : Compression et décompression de texte. 1 Généralités sur la compression/décompression de texte

Peut-on tout programmer?

Arbres binaires de recherche

Chapitre VI- La validation de la composition.

1.6- Génération de nombres aléatoires

Premiers Pas en Programmation Objet : les Classes et les Objets

# let rec concat l1 l2 = match l1 with [] -> l2 x::l 1 -> x::(concat l 1 l2);; val concat : a list -> a list -> a list = <fun>

Cours d initiation à la programmation en C++ Johann Cuenin

Programmer en JAVA. par Tama

LMI 2. Programmation Orientée Objet POO - Cours 9. Said Jabbour. jabbour@cril.univ-artois.fr

Corrigés des premiers exercices sur les classes

Projet de programmation (IK3) : TP n 1 Correction

Compression de Données - Algorithme de Huffman Document de Conception

Cours 1 : La compilation

Programmation avec des objets : Cours 7. Menu du jour

Taux d évolution moyen.

Initiation à l algorithmique

Java Licence Professionnelle CISII,

Programmation C++ (débutant)/instructions for, while et do...while

TP 1. Prise en main du langage Python

Lambda! Rémi Forax Univ Paris-Est Marne-la-Vallée

Définition des Webservices Ordre de paiement par . Version 1.0

Cours 1: Java et les objets

ARBRES BINAIRES DE RECHERCHE

Plateforme PAYZEN. Définition de Web-services

UML et les Bases de Données

Les arbres binaires de recherche

TD/TP PAC - Programmation n 3

length : A N add : Z Z Z (n 1, n 2 ) n 1 + n 2

Conception de circuits numériques et architecture des ordinateurs

Programmation Objet - Cours II

INF 321 : mémento de la syntaxe de Java

Exercices INF5171 : série #3 (Automne 2012)

Complexité. Licence Informatique - Semestre 2 - Algorithmique et Programmation

Chapitre V. Les classes : Object, Vector, etc.

Exclusion Mutuelle. Arnaud Labourel Courriel : arnaud.labourel@lif.univ-mrs.fr. Université de Provence. 9 février 2011

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Chapitre 2 Devine mon nombre!

RAPPELS SUR LES METHODES HERITEES DE LA CLASSE RACINE Object ET LEUR SPECIALISATION (i.e. REDEFINITION)

Ensimag 1ère année Algorithmique 1 Examen 2ième session 24 juin Algorithmique 1

Algorithmique, Structures de données et langage C

Généralités sur le Langage Java et éléments syntaxiques.

Structures algébriques

Introduction à JDBC. Accès aux bases de données en Java

LE PROBLEME DU PLUS COURT CHEMIN


Exercices types Algorithmique et simulation numérique Oral Mathématiques et algorithmique Banque PT

Développement Logiciel

Licence Sciences et Technologies Examen janvier 2010

PROBLEMES D'ORDONNANCEMENT AVEC RESSOURCES

Exceptions. 1 Entrées/sorties. Objectif. Manipuler les exceptions ;

Cours 1 : Introduction. Langages objets. but du module. contrôle des connaissances. Pourquoi Java? présentation du module. Présentation de Java

G.P. DNS02 Septembre Réfraction...1 I.Préliminaires...1 II.Première partie...1 III.Deuxième partie...3. Réfraction

Structurer ses données : les tableaux. Introduction à la programmation

Objets et Programmation. origine des langages orientés-objet

Cours d introduction à l informatique. Partie 2 : Comment écrire un algorithme? Qu est-ce qu une variable? Expressions et instructions

Introduction à MATLAB R

Programmation Par Objets

SHERLOCK 7. Version du 01/09/09 JAVASCRIPT 1.5

1. Qu'est-ce que SQL? La maintenance des bases de données Les manipulations des bases de données... 5

Corrigé des exercices sur les références

Compte-rendu de projet de Système de gestion de base de données

Master Modélisation Aléatoire Paris VII, Cours Méthodes de Monte Carlo en nance et C++, TP n 2.

4. Groupement d objets

Bases de programmation. Cours 5. Structurer les données

Informatique Générale

TD/TP PAC - Programmation n 3

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

Transcription:

X2012 INF421 Examen de rattrapage / 25 novembre 2013 Tous documents autorisés (poly, notes de cours, notes de PC). Dictionnaires électroniques autorisés pour les élèves étrangers. L'énoncé est composé de 2 parties indépendantes, que vous pourrez traiter dans n'importe quel ordre (en revanche, merci de clairement numéroter les réponses). Vous pourrez, quand vous traiterez une question, considérer comme déjà traitées les questions précédentes de la même partie. Le correcteur prêtera attention à la qualité de la rédaction et vous remercie d'avance d'écrire lisiblement. Merci également de numéroter vos copies en indiquant leur nombre total. 1 Le compte est bon Dans ce problème, on s'intéresse à la question suivante : quel est l'ensemble T (S) des nombres entiers que l'on peut construire, en utilisant uniquement l'addition, la soustraction et la multiplication, à partir des éléments d'un ensemble ni S d'entiers, en utilisant chaque élément de S une fois et une seule? Ainsi, à partir de l'ensemble S = {2, 3, 7 on peut construire l'entier 19 (comme 2 3 7), l'entier 6 (comme 7 (3 2)) ou encore l'entier 27 (comme 3 (2 + 7)). Au total, on peut construire 24 nombres diérents à partir de S, à savoir T (S) = { 19, 15, 11, 8, 7, 6, 2, 1, 1, 2, 6, 7, 8, 11, 12, 13, 15, 17, 19, 20, 23, 27, 35, 42. Dans la suite, on note n le cardinal de S et on suppose n < 32. On suppose qu'on se donne S sous la forme d'un tableau contenu dans un champ S de la classe dans laquelle on travaille : class Numbers { private final int[] S; Numbers(int[] S) { this.s = S; Pour résoudre le problème, on va le généraliser et chercher T (U) pour tout sous-ensemble U de S. Un sous-ensemble U de S sera représenté par un entier u. Le bit i de u, pour 0 i < n, indique la présence de l'élément S[i] dans U. (C'est la même idée que celle utilisée dans le poly et l'amphi 3 pour résoudre le problème des N reines.) Ainsi pour n = 6 et le tableau S={2,3,7,10,25,100, l'entier 42, dont l'écriture en binaire est 101010 2, représente le sous-ensemble {3, 10, 100, car les bits à 1 sont les bits de positions 1, 3 et 5 (correspondant donc à S[1], S[3] et S[5]). On commence par quelques méthodes élémentaires pour manipuler cette représentation. Question 1 Écrire une méthode boolean issingleton(int u, int i) qui renvoie true si et seulement si le sous-ensemble de S représenté par l'entier u est le singleton {S[i]. On pourra supposer 0 i < n. return u == (1 << i); 1

Question 2 Écrire une méthode boolean isincluded(int u1, int u2) qui renvoie true si et seulement si le sous-ensemble de S représenté par l'entier u1 est inclus dans le sous-ensemble de S représenté par u2. return (u1 & u2) == u1; Question 3 Écrire une méthode int setdifference(int u1, int u2) qui renvoie l'entier représentant la diérence ensembliste u1\u2, pour deux sous-ensembles de S représentés par les entiers u1 et u2. return u1 & ~u2; Une idée pour résoudre le problème donné consiste à écrire une méthode récursive TreeSet<Integer> computeall(int u) qui prend en argument un entier u représentant un sous-ensemble U de S et renvoie l'ensemble des entiers que l'on peut construire à partir de U. Pour représenter l'ensemble renvoyé, on utilise la classe TreeSet de la bibliothèque Java (un arbre binaire de recherche équilibré). Pour ce qui suit, il sut de savoir que new TreeSet<Integer>() construit un nouvel ensemble (vide), que s.add(x) ajoute l'entier x à l'ensemble s et que la notation for(int x: s) peut être utilisée pour parcourir tous les éléments d'un ensemble s. On propose la structure suivante pour la méthode computeall : TreeSet<Integer> computeall(int u) { assert (u!= 0); TreeSet<Integer> res = new TreeSet<Integer>(); // cas 1 : u est un singleton for (int i = 0; i < this.s.length; i++) if (issingleton(u, i)) { return res; // cas 2 : u est l'union disjointe de deux sous-ensembles non vides for (int left = 1; left < u; left++) if (isincluded(left, u)) { return res; Comme l'indique la première ligne du code, on suppose que le sous-ensemble U représenté par l'entier u est non vide. On distingue alors deux cas : le cas où U est un singleton et le cas où il contient au moins deux éléments. Dans ce second cas, on examine toutes les décompositions U = L R possibles, avec L et R non vides, le sous-ensemble L étant représenté par l'entier left dans le code ci-dessus. 2

Question 4 Écrire le code correspondant au premier cas (c'est-à-dire à la première occurrence de dans le code ci-dessus). res.add(this.s[i]); Question 5 (exclus). Expliquer pourquoi les valeurs de left considérées sont comprises entre 1 (inclus) et u left ne peut être plus grand que u car sinon left contiendrait des éléments qui ne sont pas dans u. Par ailleurs, 0 et u sont exclus car on cherche un sous-ensemble strict de u. Question 6 Écrire le code correspondant au second cas (c'est-à-dire à la seconde occurrence de dans le code ci-dessus). int right = setdifference(u, left); if (left < right) continue; // OPTIM TreeSet<Integer> sleft = computeall(left); TreeSet<Integer> sright = computeall(right); for (int x: sleft) { for (int y: sright) { res.add(x + y); res.add(x - y); res.add(y - x); res.add(x * y); Question 7 Écrire enn une méthode TreeSet<Integer> computeall() qui répond au problème initial, c'est-à-dire qui renvoie l'ensemble des valeurs que l'on peut construire à partir de S. return allmemo((1 << S.length) - 1); Question 8 Expliquer comment modier le programme ci-dessus pour que chaque élément de S soit utilisé au plus une fois (et non pas exactement une fois). Note : un nombre de S au moins doit être utilisé. 3

Il sut d'ajouter tous les éléments de computeall(left) à res, c'est-à-dire ajouter la ligne res.add(x); juste après la ligne for(int x: sleft). Question 9 Peut-on utiliser la technique de mémoïsation pour améliorer l'ecacité en temps de ce programme? Si oui, expliquez comment. On va être amené à calculer plusieurs fois computeall(u) pour la même valeur de u. Par exemple, dans le cas n = 3, on aura trois décompositions de S = {a, b, c, à savoir {a {b, c, {b {a, c et {c {a, b, et on appellera donc plusieurs fois computeall sur les singletons {a, {b, et {c. Pour mémoïser computeall, il sut d'introduire une table de hachage globale private HashMap<Integer, TreeSet<Integer>> memo = new HashMap<Integer, TreeSet<Integer>>(); de la consulter au début de computeall et de la remplir à la n. Question 10 Comment faire pour conserver, pour chaque entier qui peut être construit avec S, une séquence d'opérations permettant de le calculer? (S'il en existe plusieurs, on choisit arbitrairement.) On ne demande pas d'écrire le code Java, mais seulement d'indiquer une méthode. Plutôt qu'un ensemble d'entiers, on construit un ensemble de class Sol implements Comparable<Sol> { final int value; final char op; final Sol left, right; c'est-à-dire une valeur entière (champ value) et la façon dont elle a été construite (champs op, left et right). 2 Des cordes équilibrées On rappelle qu'une corde est une structure de données pour représenter des chaînes de caractères selon le principe suivant : une corde est un arbre binaire, où chaque n ud interne représente une concaténation et chaque feuille contient une chaîne de caractères usuelle. La chaîne représentée par une corde est donc la concaténation de toutes les feuilles, considérées dans l'ordre inxe. Ainsi la corde 4

+ + "Ec" (2) "ole P" (2) + "o" (2) + + "que" (3) "lytech" (4) "ni" (4) représente la chaîne "Ecole Polytechnique". La profondeur de chaque feuille est sa distance à la racine ; elle est indiquée dans l'exemple ci-dessus entres parenthèses. D'une manière générale, une corde est formée de k feuilles s 1,..., s k, aux profondeurs respectives p 1,..., p k. On dénit alors sa longueur, notée L(c), comme son nombre total de caractères, c'est-à-dire L(c) = k s i i=1 où s i désigne la longueur de la chaîne s i. On dénit la hauteur de la corde c, notée H(c), comme la profondeur maximale de ses feuilles, c'est-à-dire H(c) = max 1 i k p i. Enn, on dénit le coût d'une corde, noté C(c), comme la somme de la distance de tous ses caractères à la racine, c'est-à-dire k C(c) = p i s i. i=1 Le but de ce problème est de réaliser un algorithme d'équilibrage d'une corde, pour majorer le coût en fonction de la longueur de la corde. On rappelle qu'une corde peut être représentée en Java à l'aide d'une classe abstraite Rope, avec deux sous-classes Str et App représentant respectivement une feuille et un n ud interne. La structure est la suivante : abstract class Rope { int length; class Str extends Rope { private final String str; Str(String str) { this.str = str; this.length = str.length(); class App extends Rope { private final Rope left, right; App(Rope left, Rope right) { this.left = left; this.right = right; this.length = left.length + right.length; On note que le champ length de chaque corde c contient sa longueur L(c). La corde vide, notée empty, est la corde new Str("") (supposée construite une fois pour toutes par la suite). 5

Question 11 Écrire une méthode Rope append(rope r) qui concatène la corde this et la corde r, en prenant soin de ne pas construire de nouvelle corde lorsque L(this) = 0 ou L(r) = 0. Rope append(rope r) { if (this.length == 0) return r; if (r.length == 0) return this; return new App(this, r); Question 12 Écrire une méthode int cost() dans la classe Rope, qui calcule le coût d'une corde, c'est-à-dire C(this). Si besoin, on introduira une méthode auxiliaire, dénie diéremment dans chacune de deux sous-classes Str et App. dans la classe Rope : int cost() { return cost(0); abstract int cost(int depth); dans la classe Str : int cost(int depth) { return depth * length; et enn dans la classe App : int cost(int depth) { return this.left.cost(depth + 1) + this.right.cost(depth + 1); Autre solution : dans Str, cost renvoie 0 et dans App, cost renvoie length + left.cost() + right.cost(). On propose l'algorithme suivant pour équilibrer une corde c. On considère un tableau queue de cordes dans lequel les feuilles s 1,..., s k de c vont être insérées successivement, dans le sens des indices croissants. Les cases d'indices 0 et 1 ne sont pas utilisées. La case d'indice i contient soit la corde vide empty, soit une corde de hauteur i 2 et dont la longueur est comprise dans l'intervalle [F i, F i+1 [ où F i désigne le i-ième terme de la suite de Fibonacci. 1. On insère successivement chaque feuille s j dans queue, à partir de la case d'indice i = 2. L'insertion d'une feuille, et plus généralement d'une corde, à partir de la case d'indice i se fait ainsi : (a) On concatène, avec append, la corde à insérer avec la corde se trouvant dans la case i ; soit c i le résultat. Si la longueur de c i est comprise dans l'intervalle [F i, F i+1 [ alors on aecte c i à la case i et on a terminé l'insertion. (b) Sinon, on aecte empty à la case i et on retourne à l'étape (a) pour eectuer l'insertion de c i à partir de la case d'indice i + 1. On notera qu'on a l'invariant suivant : après l'insertion de la feuille s j, la concaténation de toutes les cordes de queue, considérées dans le sens des indices décroissants, est égale au mot s 1 s 2... s j. 6

2. Le résultat est alors la concaténation de toutes les cordes de queue, à savoir queue[m 1].append(queue[m 2].append(... (queue[3].append(queue[2])))) où m désigne la taille de queue. On rappelle que la suite de Fibonacci (F n ) est dénie par F 0 = 0, F 1 = 1, F n+2 = F n+1 + F n pour n 0. On suppose la longueur des cordes toujours inférieure à F 44. On limite donc la taille de queue à 44 cases indexées de 0 à 43 (les cases 0 et 1 n'étant pas utilisées). On introduit la constante maxfib et le tableau fib suivants static final int maxfib = 44; static final int[] fib = new int[maxfib + 1]; et on suppose que le tableau fib est rempli avec les valeurs F i pour 0 i maxfib. Pour réaliser le point 1 de l'algorithme ci-dessus, on se donne les deux méthodes void insertqueue(rope[] queue, Rope r, int i) { abstract void insertleaves(rope[] queue); dans la classe Rope. La méthode insertleaves insère toutes les feuilles de la corde this dans le tableau queue. La méthode insertqueue insère la corde r dans queue, à partir de l'indice i. Question 13 Que signie le mot clé abstract devant la méthode insertleaves? que la méthode insertleaves n'est pas implémentée dans la classe Rope, mais seulement dans ses sous-classes. Question 14 Écrire le code de la méthode insertleaves dans chacune des classes Str et App. class Str { void insertleaves(rope[] queue) { insertqueue(queue, this, 2); class App { void insertleaves(rope[] queue) { this.left.insertleaves(queue); this.right.insertleaves(queue); 7

Question 15 Écrire le code de la méthode insertqueue. On supposera 0 i < maxfib, H(r) i 2 et L(r) F i. void insertqueue(rope[] queue, Rope r, int i) { assert (i < maxfib); Rope c = queue[i].append(r); if (c.length < fib[i + 1]) queue[i] = c; else { queue[i] = empty; insertqueue(queue, c, i + 1); Question 16 Montrer que l'invariant H(queue[i]) i 2 et L(queue[i]) F i est préservé par la fonction insertqueue, sous les hypothèses de la question précédente, pour toutes les cases queue[i] du tableau queue non égales à empty, avec 2 i < maxfib. l'invariant de insertqueue est : H(c) <= i-2 et L(c) >= fib(i) - cas n' < fib.(i+1) : - si queue(i) = empty, alors c' = c et l'invariant de la file est vérifié - sinon, n' = L(c) + L(queue(i)) >= F_i + F_i >= F_{i+1 contradiction - cas n' >= fib.(i+1): on a H(c') = 1 + max(h(c),queue(i)) <= i-1 = (i+1)-2 et n' = L(c') >= fib_{i+1 donc l'invariant de insertqueue est bien préservé Question 17 Compléter la méthode balance qui réalise l'équilibrage d'une corde : Rope balance() { Rope[] queue = new Rope[maxFib]; for (int i = 0; i < maxfib; i++) queue[i] = empty; this.insertleaves(queue); Il s'agit donc de remplacer par du code réalisant le point 2 de l'algorithme donné plus haut. 8

Rope r = empty; for (int i = 2; i < maxfib; i++) r = queue[i].append(r); return r; Question 18 Soit c une corde non vide renvoyée par la méthode balance ci-dessus. Soit n sa longueur et h sa hauteur. Montrer que l'on a n F h+1. En déduire qu'il existe une constante K (indépendante de n) telle que C(c) n (log φ (n) + K), où log φ désigne le logarithme à base φ, φ étant le nombre d'or (1 + 5)/2. On admettra que F i+1 φ i / 5 pour tout i 0. n >= F_{h+1 : dans la boucle de balance, l'invariant est le suivant : si r <> empty alors H(r) <= i-2 et L(r) >= F_{H(c)+1 initialement : r = empty et l'invariant est donc trivialement vrai préservation : soit r' = queue(i).append(r) ; supposons r' <> empty - H(r') <= 1 + max(h(queue(i)), H(r)) <= 1 + max(i-2, i-2) = (i+1)-2 - si r = empty, alors r' = queue(i) et L(r') >= F_i >= F_{i-1 >= F_{H(r')+1 car H(r') = H(queue(i)) <= i-2 si r <> empty, alors L(r') = L(queue(i)) + L(r) >= F_i + F_{H(r)+1 (1) -- si H(r) >= H(queue(i)) alors H(r') = 1 + H(r) comme i >= H(r)+2 alors (1) donne L(r') >= F_{H(r)+2 + F_{H(r)+1 >= F_{H(r)+1+1 = F_{H(r')+1 9

-- si H(r) < H(queue(i)) alors H(r') = 1 + H(queue(i)) comme i >= H(queue(i))+2 alors (1) donne L(r') >= F_{H(queue(i))+2 + F_{H(r)+1 >= F_{H(queue(i))+1+1 = F_{H(r')+1 on déduit immédiatement le résultat n >= F_{h+1 de cet invariant car on a supposé r non vide à la sortie * C(c) <= : on a C(c) <= n * h or n >= F_{h+1 >= 1/sqrt{5 * phi^h donc h <= log_phi(n) + K * * * 10