Version interactive avec LaTeX compilé
INFORMATIQUE
Préliminaires :
Le sujet traite du problème du monnayeur : comment rendre la monnaie en utilisant le plus petit nombre possible de pièces? Les deux premières parties mettent en place le formalisme et les outils qui serviront pour la suite. On étudiera dans la partie III «l'algorithme glouton». La dernière partie présente un algorithme permettant de décider si l'algorithme glouton est optimal pour un système de pièces donné. Cette dernière partie utilise les résultats établis dans les parties précédentes. Il est rappelé que cette épreuve est une épreuve d'informatique, et que l'absence de programmes sera donc sanctionnée comme il se doit.
Les algorithmes demandés seront décrits en français ; les programmes seront rédigés en langage Caml ou en langage Pascal. Les candidats indiqueront impérativement au tout début de leur copie le langage de programmation qu'ils ont choisi d'utiliser.
Une approche modulaire est vivement conseillée, comme l'a indiqué René Descartes, il convient «de diviser chacune des difficultés que j'examinerais en autant de parcelles qu'il se pourrait, et qu'il serait requis pour les mieux résoudre ». Lorsque les candidats choisiront d'écrire une fonction annexe non demandée, il leur est demandé avec insistance d'expliquer avant les spécifications de cette fonction.
Certaines questions ou remarques sont réservées soit aux candidats ayant choisi le langage Caml, soit à ceux ayant choisi le langage Pascal. Dans ce cas, la question ou remarque est annoncée par un encadré, et se termine par un trait de séparation pointillé ou un nouvel encadré.
Pour les questions de complexité, on demande d'évaluer les coûts globalement en terme d'opérations élémentaires telles que des affectations, des opérations arithmétiques, comparaisons, tests... En particulier, on ne s'attachera pas à des considérations concernant la taille des données.
Les algorithmes demandés seront décrits en français ; les programmes seront rédigés en langage Caml ou en langage Pascal. Les candidats indiqueront impérativement au tout début de leur copie le langage de programmation qu'ils ont choisi d'utiliser.
Une approche modulaire est vivement conseillée, comme l'a indiqué René Descartes, il convient «de diviser chacune des difficultés que j'examinerais en autant de parcelles qu'il se pourrait, et qu'il serait requis pour les mieux résoudre ». Lorsque les candidats choisiront d'écrire une fonction annexe non demandée, il leur est demandé avec insistance d'expliquer avant les spécifications de cette fonction.
Certaines questions ou remarques sont réservées soit aux candidats ayant choisi le langage Caml, soit à ceux ayant choisi le langage Pascal. Dans ce cas, la question ou remarque est annoncée par un encadré, et se termine par un trait de séparation pointillé ou un nouvel encadré.
Pour les questions de complexité, on demande d'évaluer les coûts globalement en terme d'opérations élémentaires telles que des affectations, des opérations arithmétiques, comparaisons, tests... En particulier, on ne s'attachera pas à des considérations concernant la taille des données.
Notations:
- Lorsque
est un ensemble fini, désigne son cardinal. - Lorsque
désigne la partie entière inférieure de , et sa partie entière supérieure: ce sont les uniques entiers relatifs vérifiant et . - si
avec , désigne l'ensemble des entiers relatifs compris entre et . - Si
est muni de sa structure euclidienne canonique en posant, pour .
Filière MP
- Si
désigne le -uplet dont toutes les composantes sont nulles sauf la -ème qui vaut 1 .
Formalisation du problème :
Soit
un
-uplet d'entiers vérifiant
.
Nous utiliserons le terme système pour désigner un tel -uplet. Les
sont les valeurs faciales des pièces en service. Par exemple, le système utilisé en zone Euro est (200, 100, 50, 20, 10, 5, 2, 1).
Pour chaque, , nous disposons d'une quantité illimitée de pièces de valeur
. Soit
un entier (le montant à rendre). Une représentation de
dans le système
est un
-uplet
vérifiant:
Nous utiliserons le terme système pour désigner un tel
Pour chaque,
Pour épargner les poches des clients, nous souhaitons minimiser le poids de cette représentation, c'est-à-dire la quantité:
avec
(le
-uplet dont toutes composantes sont égales à 1 ).
Partie I - Systèmes de pièces
Note à l'attention des candidats qui ont choisi le langage Caml
Nous utiliserons des listes d'entiers pour représenter aussi bien un système (liste de valeurs de pièces) qu'une représentation d'un montant dans ce système. Par exemple, la liste
est une représentation de 30 dans le système (
).
La question suivante est destinée aux candidats qui ont choisi le langage Caml
I.A - Rédiger en Caml une fonction de signature
est_un_systeme : int list -> bool
spécifiée comme suit:est_un_systeme c indique si la liste c est bien un système. Par exemple, est_un_systeme rendra la valeur true, tandis que est_un_systeme [
]rendra la valeur false, tout comme le fera est_un_systeme
.
est_un_systeme : int list -> bool
spécifiée comme suit:est_un_systeme c indique si la liste c est bien un système. Par exemple, est_un_systeme
Note à l'attention des candidats qui ont choisi le langage Pascal.
Nous utiliserons des listes d'entiers pour représenter aussi bien un système (liste de valeurs de pièces), qu'une représentation d'un montant dans ce système. Le type utilisé est défini comme suit :
type Liste = ^Cellule;
type Cellule =
record
contenu : integer;
suivant : Liste
end ;
La liste vide est représentée par la constante nil. Pour créer des listes, nous disposons d'une procédure et d'une fonction dont les en-têtes sont :
procedure pCons(x:integer; var c:Liste);
function fCons(x:integer; c:liste):Liste;
spécifiées comme suit : ajoute en tête de liste c une cellule dont le champ contenu vaut x .
rend une liste dont la première cellule contient x dans son champ contenu, et dont le champ suivant vaut c .
Par exemple, le programme suivant construit les listes et
dont il sera question dans la suite.
procedure pCons(x:integer; var c:Liste);
function fCons(x:integer; c:liste):Liste;
spécifiées comme suit :
Par exemple, le programme suivant construit les listes
var L1,L2,L3:Liste;
begin
L1:=nil; pCons(1,L1); pCons(2,L1) ; pCons(5,L1);
L2:=fCons(5,fCons(7,fCons(1,nil)));
L3:=fCons(7,fCons(5,fCons(2,nil)));
end;
La question suivante est destinée aux candidats qui ont choisi le langage Pascal.
I.B - Rédiger en Pascal une fonction d'en-tête
function est_un_systeme(c:Liste):boolean;
spécifiée comme suit:est_un_systeme(c) indique si la liste c est bien un système. Par exemple, est_un_systeme(L1) rendra la valeur true, tandis que est_un_systeme(L2) rendra la valeur false, tout comme le fera est_un_systeme(L3).
I.B - Rédiger en Pascal une fonction d'en-tête
function est_un_systeme(c:Liste):boolean;
spécifiée comme suit:est_un_systeme(c) indique si la liste c est bien un système. Par exemple, est_un_systeme(L1) rendra la valeur true, tandis que est_un_systeme(L2) rendra la valeur false, tout comme le fera est_un_systeme(L3).
Partie II - Représentations de poids minimal
Soient
un système et
. Nous notons
(ou même
lorsqu'aucune ambiguïté n'est à craindre) le plus petit nombre de pièces nécessaires pour représenter
dans le système c :
Nous nous intéresserons aux représentations de poids minimal de
: ce sont les représentations
telles que
. Pour alléger la rédaction, nous parlerons simplement de représentations minimales.
II.A - Prouver l'encadrement
II.A - Prouver l'encadrement
II.B - Exhiber un système
et un nombre
possédant plusieurs représentations dans ce système.
II.C - Soient un système et
. Montrer que
pour tout indice
tel que
.
II.D - Soient un système,
, et
tel que
. Montrer soigneusement que
si, et seulement si, il existe une représentation minimale
de
, faisant intervenir
(c'est-à-dire telle que
).
II.E - Soit ; notons
le plus petit indice
tel que
. Justifier l'égalité
II.C - Soient
II.D - Soient
II.E - Soit
II.F - Soit
. Montrer que l'on peut construire la liste des valeurs de
pour
, pour un coût
(au sens précisé dans les préliminaires).
La question suivante est destinée aux candidats qui ont choisi le langage Caml.
II.G - Rédiger en Caml une fonction de signature :
poids_minimaux : int -> int list -> int list
spécifiée comme suit: poids_minimaux x c construit la liste des valeurs de pour
. Par exemple, poids_minimaux
rendra la liste
. Cet exemple fournit d'ailleurs l'ordre dans lequel on souhaite que les
apparaissent dans la liste résultat.
On utilisera la formule de la question II.E). De plus, on pourra utiliser, si on le souhaite, les fonctions list_of_vect, vect_of_list et make_vect de signatures respectives :
list_of_vect :'a vect -> 'a list
vect_of_list :'a list -> 'a vect
make_vect : int -> 'a -> 'a vect
La question suivante est destinée aux candidats qui ont choisi le langage Pascal.
II.H - Rédiger en Pascal une fonction d'en-tête
function poids_minimaux(x:integer; c:Liste):Liste;
spécifiée comme suit : poids_minimaux ( ) rendra une liste des valeurs de
, pour
. Par exemple, poids_minimaux (
) rendra la liste (
). Cet exemple fournit d'ailleurs l'ordre dans lequel on souhaite que les
apparaissent dans la liste résultat.
On utilisera la formule de la question II.E, et on pourra employer librement la constante mMax, le type vecteur, la fonction vecteur_vers_liste et la procédure liste_vers_vecteur qui pourraient être définis ainsi :
const mMax =1000;
type vecteur = array[1..mMax] of integer;
function vecteur_vers_liste(v:vecteur; r:integer):Liste;
var
p:Liste;
k:integer;
begin
p:= nil;
for downto 1 do pCons(v[k],p);
II.G - Rédiger en Caml une fonction de signature :
poids_minimaux : int -> int list -> int list
spécifiée comme suit: poids_minimaux x c construit la liste des valeurs de
On utilisera la formule de la question II.E). De plus, on pourra utiliser, si on le souhaite, les fonctions list_of_vect, vect_of_list et make_vect de signatures respectives :
list_of_vect :'a vect -> 'a list
vect_of_list :'a list -> 'a vect
make_vect : int -> 'a -> 'a vect
La question suivante est destinée aux candidats qui ont choisi le langage Pascal.
II.H - Rédiger en Pascal une fonction d'en-tête
function poids_minimaux(x:integer; c:Liste):Liste;
spécifiée comme suit : poids_minimaux (
On utilisera la formule de la question II.E, et on pourra employer librement la constante mMax, le type vecteur, la fonction vecteur_vers_liste et la procédure liste_vers_vecteur qui pourraient être définis ainsi :
const mMax =1000;
type vecteur = array[1..mMax] of integer;
function vecteur_vers_liste(v:vecteur; r:integer):Liste;
var
p:Liste;
k:integer;
begin
p:= nil;
for
vecteur_vers_liste:=p
end;
procedure liste_vers_vecteur (L:Liste; var v:vecteur;var
taille:integer);
begin
taille:=0;
while L<>nil do
begin
taille:=taille+1
v[taille]:=L^.contenu;
L:=L^.suivant
end
end;
Ainsi, vecteur_vers_liste(v,r) retourne la liste des
sous réserve que l'encadrement
soit vérifié. Si
, elle rend la liste vide; si
, le résultat n'est pas spécifié.
L'appel liste_vers_vecteur( ) place quant à lui les éléments de la liste
dans un vecteur
, en mettant à jour la variable
représentant le nombre d'éléments de la liste.
L'appel liste_vers_vecteur(
Partie III - L'algorithme glouton
Avertissement : Dans cette partie, on travaillera obligatoirement sur des listes sans passer par des vecteurs.
L'algorithme glouton pour rendre une somme consiste à choisir le plus grand
, puis à rendre récursivement
. Par exemple, avec le système
, l'algorithme décomposera 27 en
. Avec le formalisme proposé, la solution fournie par l'algorithme glouton est donc
. Le fonctionnement de l'algorithme glouton peut être accéléré par la remarque suivante :
notant , cet algorithme rend
pièces de valeur
, puis rend le montant
en utilisant le système (
).
L'algorithme glouton pour rendre une somme
notant
La question suivante est destinée aux candidats qui ont choisi le langage Caml.
III.A - Rédiger en Caml une fonction de signature :
glouton : int -> int list -> int list
spécifiée comme suit: glouton x c construit la représentation de dans le système
en utilisant l'algorithme glouton.
Par exemple, glouton 13 [ ] rendra la liste [
].
La question suivante est destinée aux candidats qui ont choisi le langage Pascal.
III.B - Rédiger en Pascal une fonction d'en-tête
function glouton(x:integer; c:Liste):Liste;
spécifiée comme suit : glouton ( ) retourne une liste contenant la représentation de
dans le système
, en appliquant l'algorithme glouton. Par exemple, glouton (
) retournera la liste (
).
III.A - Rédiger en Caml une fonction de signature :
glouton : int -> int list -> int list
spécifiée comme suit: glouton x c construit la représentation de
Par exemple, glouton 13 [
La question suivante est destinée aux candidats qui ont choisi le langage Pascal.
III.B - Rédiger en Pascal une fonction d'en-tête
function glouton(x:integer; c:Liste):Liste;
spécifiée comme suit : glouton (
Soient
un système et
. Nous noterons
la représentation gloutonne de
dans le système
, (c'est-à-dire la représentation obtenue en appliquant l'algorithme glouton), et
(ou même
lorsqu'aucune ambiguïté n'est à craindre) le nombre de pièces utilisées par l'algorithme glouton :
.
Nous dirons qu'un système est canonique lorsque l'algorithme glouton nous donne toujours une représentation minimale ; on a alors
pour tout
.
III.C - Montrer que tout système est canonique.
III.D - Exhiber un système non canonique (en justifiant).
III.E - Soient et
deux entiers
. Montrer que le système
est canonique.
III.F - Montrer que le système «Euro» (200, 100, 50, 20, 10, 5, 2, 1) est canonique.
Nous dirons qu'un système
III.C - Montrer que tout système
III.D - Exhiber un système
III.E - Soient
III.F - Montrer que le système «Euro» (200, 100, 50, 20, 10, 5, 2, 1) est canonique.
On pourra montrer que dans une représentation minimale de
:
, on a
III.G - Avant la réforme de 1971 (introduisant un système décimal), le Royaume-Uni utilisait le système ( ). Montrer que ce système n'est pas canonique.
III.G - Avant la réforme de 1971 (introduisant un système décimal), le Royaume-Uni utilisait le système (
Partie IV - L'algorithme de Kozen et Zaks
Nous allons voir ici un algorithme efficace permettant de déterminer si un système
est canonique. Nous dirons qu'un entier
est un contre-exemple pour
si
. Un système canonique n'admet donc pas de contre-exemple.
Dans la suite,
.
IV.A - Soit
un système non canonique. Il admet donc des contre-exemples. Montrer que le plus petit d'entre-eux, disons
, vérifie :
Pour la seconde inégalité, on pourra raisonner par l'absurde et utiliser la question II.D.
IV.B - Soit . Montrer que le système (
) n'est pas canonique. Quel est le plus petit contre-exemple pour ce système ? Justifier.
IV.C - Soit . Déterminer
tel que le système (
) ne soit pas canonique, et admette
comme plus petit contre-exemple.
IV.D - Que vient-on de faire dans les deux questions précédentes ?
IV.B - Soit
IV.C - Soit
IV.D - Que vient-on de faire dans les deux questions précédentes ?
Le résultat de la question IV.A nous donne un algorithme déterminant si un système est canonique : il suffit de rechercher un contre-exemple dans l'intervalle discret
. Ceci nécessiterait la construction (coûteuse) des représentations minimales de chacun des éléments de cet intervalle.
Nous allons étudier un algorithme plus efficace, dû à Kozen et Zaks. Leur méthode repose sur la notion de témoin. Nous dirons qu'un entier est un témoin pour le système
s'il existe un indice
tel que
et
.
IV.E - Montrer que tout témoin est un contre-exemple.
IV.F - Montrer que le résultat précédent n'admet pas de réciproque.
Nous allons étudier un algorithme plus efficace, dû à Kozen et Zaks. Leur méthode repose sur la notion de témoin. Nous dirons qu'un entier
IV.E - Montrer que tout témoin est un contre-exemple.
IV.F - Montrer que le résultat précédent n'admet pas de réciproque.
On pourra travailler dans le système
.
IV.G - Montrer que si le système admet des contre-exemples, alors le plus petit d'entre eux est un témoin.
Il résulte de cette étude que, pour savoir si un système est canonique, il suffit de vérifier l'inégalité pour tout
, et tout indice
tel que
. C'est le principe de l'algorithme de Kozen et Zaks.
IV.H - En utilisant l'algorithme de Kozen et Zaks, montrer que les systèmes et
sont canoniques, alors que
ne l'est pas.
IV.G - Montrer que si le système
Il résulte de cette étude que, pour savoir si un système est canonique, il suffit de vérifier l'inégalité
IV.H - En utilisant l'algorithme de Kozen et Zaks, montrer que les systèmes
La question suivante est destinée aux candidats qui ont choisi le langage Caml.
IV.I - Rédiger en Caml une fonction de signature :
kozen_zaks : int list -> bool
spécifiée comme suit: kozen_zaks c indique si la liste est canonique. Par exemple, kozen_zaks
rendra la valeur true et kozen_zaks [
] rendra la valeur false. On utilisera l'algorithme de Kozen et Zaks.
IV.I - Rédiger en Caml une fonction de signature :
kozen_zaks : int list -> bool
spécifiée comme suit: kozen_zaks c indique si la liste
La question suivante est destinée aux candidats qui ont choisi le langage Pascal.
IV.J - Rédiger en Pascal une fonction d'en-tête
function kozen_zaks(c:Liste):boolean;
spécifiée comme suit: kozen_zaks(c) indique si la liste est canonique. Par exemple, kozen_zaks (L1) rendra la valeur true. On utilisera l'algorithme de Kozen et Zaks.
IV.K - Montrer que le coût de l'algorithme de Kozen et Zaks peut être exponentiel, par rapport au nombre de pièces du système.
On exhibera deux systèmes (l'un canonique, l'autre pas) pour lesquels le coût de l'algorithme est exponentiel en .
IV.J - Rédiger en Pascal une fonction d'en-tête
function kozen_zaks(c:Liste):boolean;
spécifiée comme suit: kozen_zaks(c) indique si la liste
IV.K - Montrer que le coût de l'algorithme de Kozen et Zaks peut être exponentiel, par rapport au nombre
On exhibera deux systèmes (l'un canonique, l'autre pas) pour lesquels le coût de l'algorithme est exponentiel en
FIN
À titre culturel, on signale l'existence d'un algorithme, dû à Pearson, résolvant le même problème mais dont le coût est polynômial en
dans le pire des cas.
