Département d’informatique et de génie logiciel Université Laval Professeur : Clermont Dupuis Bureau : 3976 IFT-21937 Introduction à l’algorithmique et à la programmation Examen sur 35 Date : 19 octobre 2006 Aucune documentation permise. Question # 1. (2 points) (i) Vous partez de la ville de Québec pour vous rendre à la ville de Montréal. Chaque pas que vous faites vous permet de franchir la moitié de la distance qui vous reste à parcourir pour atteindre la ville de Montréal. Votre stratégie pour vous rendre à la ville de Montréal correspond-elle à un algorithme ? Expliquez. Non, car cette stratégie donne lieu à un nombre infini d’opérations élémentaires. (ii) Expliquez pourquoi une recette de cuisine ne correspond pas à un algorithme la plupart du temps ? Parce qu’un algorithme doit être une procédure non ambigüe. On retrouve souvent dans une recette de cuisine des opérations qui laissent place à interprétation (par ex., ajouter une à deux pincées de sel). Question # 2. (2 points) Afin de choisir l’algorithme le plus efficace pour résoudre un problème, nous pouvons opter pour une approche théorique en effectuant une analyse en pire cas. Décrivez cette approche théorique en pire cas et illustrez à l’aide d’un exemple concret. Cette approche théorique consiste à calculer le nombre d’opérations élémentaires nécessaires à l’algorithme pour résoudre le problème. En effectuant une analyse en pire cas, il s’agit de calculer le # d’opérations élémentaires nécessaires à l’algorithme pour résoudre le problème dans le pire cas (les données du problème où l’algorithme est le plus coûteux). Exemple : La recherche séquentielle d’un mot dans le dictionnaire en commençant notre recherche à la première page du dictionnaire. La pire situation où l’algorithme sera le moins performant intervient lorsque le mot recherché se trouve dans la dernière page du dictionnaire. Question # 3. (3 points) Concevoir un algorithme (et non un programme) qui lit en entrée un entier positif n et détermine si n est un nombre premier ou non. 1. Lire un entier positif n. 2. Pour chaque valeur de i entre 2 et n 2.1 Si le reste de la division de n par i est égale à 0 (i est facteur de n) alors 2.1.1 Écrire que le nombre n n’est pas premier. 2.1.2 L’algorithme prend fin. 3. Écrire que le nombre n est premier. 4. L’algorithme prend fin. Question # 4. (1 point) Qu’est-ce qu’un compilateur ? C’est un programme informatique permettant de traduire un programme écrit dans un langage de haut niveau tel que C ou C++ en langage d’assemblage plus près de la machine. Question # 5. (2 points) Qu’entend-on par la méthode de raffinement successif pour concevoir un algorithme ? Une première version de l'algorithme est obtenue où les étapes de cet algorithme ne sont probablement pas assez détaillées pour que l’algorithme puisse être implanté. Chaque étape doit donc être affinée en une suite d'étapes plus élémentaires, chacune étant spécifiée d'une manière plus détaillée que dans la première version. Le processus de raffinement se termine lorsque l’algorithme est décrit uniquement à partir d’opérations élémentaires. Question # 6. (2 points) (i) Donnez la représentation en base 2 du nombre 25 en base 10. 110012 (ii) Donnez la valeur décimale du nombre 10101 en base 2. 16 + 4 + 1 = 21. Question # 7. (2 points) Étant donné les instructions suivantes : 2 char a = 3; int b = 4; float c; cout << (c = (float) a / b); quelles sont les conversions effectuées dans cette dernière instruction et quelle est la donnée affichée ? Le type de la variable a est convertie en float; a / b entraîne alors une conversion implicite du type de la variable b en float. On obtient alors comme résultat de la division réelle 0.75, un type float. Puisque c est de type float, c prend la valeur 0.75 sans conversion. char a=3; int b = 4; cout << (c = (float) a / b); Ex. : float c; 0.75 conversion automatique en float conversion forcée en float Question # 8. (2 points) Étant donné les instructions suivantes : int r = 1, b = 5; i = 3; while (i > 0) { if (i%2 == 0) { b = b b; i = i / 2; } else { r = r *b; i--; } } que contiennent les variables r, b et i à chaque itération ? r b i 1 5 5 125 5 5 25 25 3 2 1 0 3 À la sortie de la boucle, r contient la valeur de 53. Question # 9. (1 point) Construire la table de vérité de cette expression où p est une variable booléenne et montrez que cette expression est toujours fausse : p && !p p && !p v f fv f f vf Question # 10. (1 point) Dans la portion de programme suivante, dites pourquoi l’instruction d’affectation k = 5; doit être déplacée ? À quel endroit devrait-elle être placée sans changer le résultat affiché. int k; for (int i = 1; i <= 10; i++) { k = 5; cout << i + k; } Puisque k ne change pas de valeur au cours de chaque itération de la boucle, on devrait exécuter l’instruction d’affectation une seule fois avant d’exécuter la boucle for. Question # 11. (2 points) Dans la portion de programme suivante, on retrouve une erreur de logique classique : int k = 1; while (k <= 10) { for (int i = 1; i <= k; i++) cout << '*'; cout << endl; } À l’affichage, on compte obtenir le résultat suivant : * ** *** **** ***** 4 ****** ******* ******** ********* ********** Indiquez l’erreur et comment la corriger ? Dans la boucle while, la variable k n’est pas incrémentée de sorte que nous avons une boucle infinie. Pour corriger la situation, ajouter à la fin de chaque itération l’instruction k = k + 1; Question # 12. (5 points) Écrire un programme qui lit en entrée les valeurs entières A, B et C représentant respectivement la longueur de chaque côté d’un triangle. Supposons que A représente la longueur du côté le plus long, B et C la longueur des deux autres côtés, alors il s’agit d’afficher l’un ou l’autre des messages de la colonne de droite : A≥ B+C A2 = B2 + C2 A2 < B2 + C2 A2 > B2 + C2 Ce n’est pas un triangle. C’est un triangle rectangle. C’est un triangle aigu. C’est un triangle obtu. #include <iostream.h> void main() { int A, B, C; int Diff; cout << "Entrez la longueur des 3 cotes d'un triangle" << " en commencant par le plus long : " << endl; cin >> A >> B >> C; Diff = A * A - B * B - C * C; if (A >= B + C) cout << "Ce n'est pas un triangle." << endl; else { if (Diff == 0) cout << "C'est un triangle rectangle." << endl; else if(Diff < 0) cout << "C'est un triangle aigu." << endl; else cout << "C'est un triangle obtu." << endl; } } 5 Question # 13. (5 points) Écrire un programme qui lit en entrée N entiers, détermine le plus grand entier parmi les N entiers et, finalement, affiche le maximum obtenu. Note : On suppose que N = 10 dans ce programme. #include <iostream.h> void main() { const int nombre_d_entiers = 10; int entier, max, i = 1; // le # d’entiers à lire. // un entier à lire. // le maximum parmi les entiers. // indice de boucle. while (i <= nombre_d_entiers) { cout << "Entrez la " << i << " ieme valeur : "; cin >> entier; if (i == 1) max = entier; else if (max < entier) max = entier; i = i + 1; } cout << "Le plus grand entier est : " << max << "." << endl } Question # 14. (5 points) 6 Une année est bissextile tous les 400 ans; les siècles ne sont pas bissextiles et une année sur 4 est bissextile 1. Lire une année n. 2. Si n possède comme facteur 400 alors 2.1 Écrire que n est une année bissextile. 2.2 L’algorithme prend fin. 3. Si n possède comme facteur 100 alors 3.1 Écrire que n n’est pas une année bissextile. 3.2 L’algorithme prend fin. 4. Si n possède comme facteur 4 alors écrire que n est une année bissextile. sinon écrire que n n’est pas une année bissextile. 5. L’algorithme prend fin. Écrire un programme en C++ qui traduit l’algorithme précédent. #include <iostream.h> int main() { int annee; cout << "Entrez l'annee desiree : "; cin >> annee; if ((annee % 400) == 0) { cout << "oui." << endl; return 0; } if ((annee % 100) == 0) { cout << "non." << endl; return 0; } if ((annee % 4) == 0) cout << "oui." << endl; else cout << "non." << endl; return 0; } °°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°°° 7