Jean-Jacques Lévy Yves Robert
20 décembre 2000 -- 2h
A. Décompositions d'entiers
Question 1
class ListeDecomp {
int val;
ListeDecomp suivant;
ListeDecomp (int v, ListeDecomp x) { val = v; suivant = x; }
static boolean estDecomp (ListeDecomp x, int n) {
int somme = 0;
for (ListeDecomp y = x; y != null; y = y.suivant)
if (y.val <= 0) return false;
else somme = somme + y.val;
return n == somme;
}
}
Question 2(1,1,1,1,1) < (1,1,1,2) < (1,1,2,1) < (1,1,3) < (1,2,1,1) <
(1,2,2) < (1,3,1) <(1,4) < (2,1,1,1) < (2,1,2) < (2,2,1) < (2,3) <
(3,1,1) < (3,2) < (4,1) < (5). On modifie 2 chiffres (et on ajoute
éventuellement des 1) dans toute décomposition pour passer à la
suivante.
Question 3Bien penser au cas n = 0 dans ce test.
static boolean estMax (ListeDecomp x, int n) {
if (x == null) return n == 0;
else return x.val == n && x.suivant == null;
}
Question 4Si les deux derniers chiffres sont i et j, on passe au
suivant en les changeant par i+1 suivi par j-1 fois 1.
static ListeDecomp suivante (ListeDecomp x) {
if (x.suivant.suivant == null) {
ListeDecomp r = null;
for (int i = 0; i < x.suivant.val - 1; ++i)
r = new ListeDecomp (1, r);
return new ListeDecomp (x.val + 1, r);
} else return new ListeDecomp (x.val, suivante (x.suivant));
}
B. Partage équilibré de périmètre
Question 5Le coût est clairement linéaire pour une coupe donnée. Comme il y a
un nombre quadratique de coupes, le coût total est en O(n3).
Question 6a)
static int perimetre (int[] a) {
int p = 0;
for (int k = 0; k < a.length; ++k)
p = p + a[k];
return p;
}
b) Soit p le périmètre. Pour un indice i donné, posons
sk = a[i] + a[i+1] + ··· a[k] et s'k = p - sk. On cherche à
minimiser |s'k-sk| = |p - 2sk|. Clairement le minimum est autour
de p - 2sk = 0. Et donc pour sk Î {ë p/2û, ë
p/2û + 1}.
c) On en déduit la fonction cherchée. Pour chaque valeur de
i, la recherche de j est linéaire, d'où un coût total en
O(n2).
static void partage1(int[] a) {
int n = a.length, j, iMin = 0, jMin = 0;
int p = perimetre (a), dMin = p; int d;
for (int i = 0; i < n; ++i) {
int k = i; int s = a[i];
while (2*s <= p) { k = (k + 1 ) % n; s = s + a[k]; }
int delta = Math.abs(p - 2*(s-a[k]));
int delta1 = Math.abs(p - 2*s);
if (delta < delta1) { j = k; d = delta; }
else { j = (k+1) % n ; d = delta; }
if (d < dMin) {
iMin = i; jMin = j; dMin = d;
}
}
System.out.println("i= " + iMin + ", j = " + jMin + ", d = " + dMin);
}
Question 7On réutilise la valeur courante de s en passant d'une
valeur de i à la suivante: k ne peut qu'augmenter et ne peut
d'ailleurs faire plus de deux tours au fil de l'exécution.
static void partage2(int[] a) {
int n = a.length, j, iMin = 0, jMin = 0;
int p = perimetre (a), dMin = p, d; int s = 0; int k = 0;
for (int i = 0; i < n; ++i) {
s = (i == 0) ? a[0] : s - a[i-1] ;
while (2*s <= p) { k = (k + 1 ) % n; s = s + a[k]; }
int delta = Math.abs(p - 2*(s-a[k]));
int delta1 = Math.abs(p - 2*s);
if (delta < delta1) { j = k; d = delta; }
else { j = (k+1) % n ; d = delta; }
if (d < dMin) {
iMin = i; jMin = j; dMin = d;
}
}
System.out.println("i= " + iMin + ", j = " + jMin + ", d = " + dMin);
}
This document was translated from LATEX by HEVEA.