0% ont trouvé ce document utile (0 vote)
110 vues34 pages

Corrigés TD Algorithmique Avancée

Ce document contient des exercices sur la complexité des algorithmes avec des questions sur le calcul du PGCD, l'algorithme d'Euclide, l'analyse asymptotique et la complexité d'algorithmes itératifs et récursifs. Le document est long et détaille de nombreux concepts liés à l'analyse de la complexité des algorithmes.

Transféré par

il
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
110 vues34 pages

Corrigés TD Algorithmique Avancée

Ce document contient des exercices sur la complexité des algorithmes avec des questions sur le calcul du PGCD, l'algorithme d'Euclide, l'analyse asymptotique et la complexité d'algorithmes itératifs et récursifs. Le document est long et détaille de nombreux concepts liés à l'analyse de la complexité des algorithmes.

Transféré par

il
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Corrigés - Travaux Dirigés Algorithmique

Avancée

1 Introduction à la complexité des algorithmes


Exercice 1 Calcul du plus grand commun diviseur (PGCD).

Question 1 Pour montrer qu’un algorithme est correct, il faut montrer qu’il ter-
mine et qu’il renvoie le résultat attendu.
— Terminaison :
— Avant et après la boucle “tant que” il y a un nombre constant d’opé-
rations.
— Dans la boucle “tant que” il y a un nombre constant d’opérations.
— La boucle “tant que” s’exécute au plus n fois (si t = 1 alors m mod t =
n mod t = 0)

1
— L’algorithme renvoie le résultat attendu pour n’importe quelle donnée :
— Le premier “si” est correct (si n = 0 alors le PGCD est 0).
— Invariant de boucle : t ≥ P GCD(m, n)
1. Initialisation : le PGCD est plus petit que n, donc correct.
2. Conservation : On suppose que l’invariant est vrai au début d’une
itération, on montre qu’il est vrai au début de l’opération suivante.
Puisque t ≥ P GCD(m, n), si m mod t ̸= 0 et n mod t ̸= 0 alors
t > P GCD(m, n) et donc l’invariant est vrai au début de l’itération
suivante.
3. Terminaison : La boucle termine si t est un diviseur de m et de n,
puisque t ≥ P GCD(m, n), alors t = P GCD(m, n) d’où le résultat.

Question 2 Le meilleur des cas est m = n, et dans ce cas il y a un nombre constant


d’opération puisque P GCD(m, n) = m = n.

Question 3 Le pire des cas est lorsque m n’a pas de diviseur commun avec n, par
exemple quand m est un nombre premier. Dans ce cas PGCD_brute-force
passe n fois dans la boucle, et donc le nombre d’opérations est cn où c est
une constante.

Exercice 2 Algorithme d’Euclide.


Question 4 Invariant de boucle : P GCD(m, n) (c’est à dire avant chaque itération
de la boucle principale, le P GCD(m, n) ne change pas)

Question 5 — Initialisation : tautologie


— Conservation : à chaque itération de la boucle, m prend la valeur de n et
n prend la valeur de m mod n. Il faut donc prouver que P GCD(m, n) =
P GCD(n, m mod n). Soit p = P GCD(m, n), r = m mod n et p′ =
m
P GCD(n, r). On a m = kn+r avec k ∈ Z. Ceci implique que p = k np + pr .

2
Par conséquence, p divise r car m n ′
p ∈ N et p ∈ N . Et donc p ≤ p puisque
p divise n et r. D’autre part, m n r ′ n
p′ = k p′ + p′ implique p divise m car p′ ∈ N
et pr′ ∈ N. Donc p′ ≤ p car p = P GCD(m, n). D’où p = p′ .

— Terminaison : La boucle termine si n est nul, c’est à dire si m mod n = 0


à l’itération précedente. Dans ce cas, à l’intération précédente on avait
P GCD(m, n) = n et donc en sortant de la boucle m contient cette valeur.

Question 6 Non : m mod n est toujours plus petit que n, donc le nombre d’itéra-
tions ne peut pas être supérieur à n.

Question 7 — Si n ≤ m/2 alors m mod n < m/2 puisque m mod n < n.


— Si n > m/2 alors m mod n = m − n < m/2

Question 8 Le pire des cas est le même : lorsque m et n n’ont aucun commun
diviseur. Dans ce cas là on s’arrête lorsque n = 0. Considérons les valeurs
successive de n à chaque début itération dans l’ordre inverse. La première
valeur est positive, et après 2 itérations, par le résultat de la question précé-
dentes, la valeur de n est au moins doublée. Donc si on a k itération, alors
k
n ≥ 2 2 . Autrement dit le nombre d’itérations k est tel que k ≤ 2 log2 n.

3
2 Analyse asymptotique et complexité d’algorithmes itératifs
Exercice 1 Utiliser la complexité algorithmique.
Question 1


— 1.C : Pour l’algorithme en O(n2 ), on a 100n20 = n21 , et donc n1 = 100×n0

Question 2

— 2.C : Pour l’algorithme en O(2n ), on a 100 · 2n0 = 2n1 , et donc n1 =


log 100 + n0

Question 3 L’algorithme A prends un temps T (A) ≃ cA · n2 , et l’algorithme B


prends un temps T (B) ≃ cB · n log n. Calculons les constantes cA et cB :
1
— cA = 1/1002 = 10000 s
1
— cB = 20/(100 × 2) = 10 s

Maintenant on peut prédire le temps de calcul en fonction de la taille de la


donnée :
n = 100 n = 1000 n = 10000
A 1s 100s 10000s
B 20s 300s 4000s

Exercice 2 Notations asymptotiques.


Question 4 Lesquelles des assertions suivantes sont vraies ?

4
1. 1000 ∈ O(1) 16. (n + 1) ∗ ( n2 − 1) ∈ Θ(n2 )
2. n2 ∈ Ω(n3 ) (f) 17. n3 + 3n2 + n + 2017 ∈ O(n3 )
3. n3 ∈ Ω(n2 ) 18. n2 ∗ n3 ∈ O(n3 ) (f)
1 2
4. 2n+1 ∈ O(2n ) 19. 2n − 3n ∈ Θ(n2 )
1 2
5. (n + 1)2 ∈ Θ(n2 ) 20. 4n ∗ Ω(n) ∈ Ω(n3 )
6. n3 + 12 ∈ O(2n ) 21. log2 (2n) ∈ Θ(log n)

7. n ∈ Θ(n) (f) 22. log2 (n2 ) ∈ Θ(log n)
8. π 32 ∈ O(1) 23. (log2 (n))2 ∈ Θ(log n) (f)
9. (n − 3)(n + 1) ∈ O(n3 ) 24. 3n ∈ O(2n ) (f)
10. n3 m2 ∈ O(m6 ) (f) 25. 2n+3 ∈ O(2n )
11. 2(n−12) ∈ Ω(2n ) 26. 23n ∈ O(2n ) (f)
12. 3n ∈ O(2n ) (f) 27. Si g(n) ∈ O(f (n)) alors 2g(n) ∈ O(2f (n) ) (f)
13. n3.14 ∈ Θ(n3 ) (f) 28. Si g(n) ∈ Θ(f (n)) alors |g(n) − f (n)| ∈ Θ(1) (f)
g(n)
14. n3.14 ∈ O(n3 ) (f) 29. Si g(n) ∈ Θ(f (n)) alors f (n) ∈ Θ(1)
15. n3.14 ∈ Ω(n3 ) 30. Θ(f (n)) ⊆ O(f (n))

Question 5 Est-ce que les propositions suivantes sont vraies pour tout f, g ? Pour
chacune, prouvez-le ou trouvez un contre-exemple (si un contre-exemple est
nécessaire, un schéma sans analyse numérique sera suffisant).
(5.a) f (n) ∈ Ω(g(n)) alors g(n) ∈ O(f (n))
(5.b) f (n) ∈ O(g(n)) ou g(n) ∈ O(f (n))

— (5.a) est vrai :


— ⇒ : ∃c∃n0 ∀n ≥ n0 f (n) ≥ cg(n) donc ∀n ≥ n0 g(n) ≤ 1c f (n) ;
— ⇐ : similaire
— (5.b) est fausse : par exemple avec f (n) = n et g(n) = n ∗ nsin(n) (il suffit de
schématiser deux fonctions ayant ce type de comportement)
Question 6 Prouvez que O(max(f (n), g(n)) = O(f (n) + g(n)).

Equivalent à prouver que h(n) ∈ O(max(f (n), g(n))) ⇔ h(n) ∈ O(f (n) + g(n))
— ⇒ : h(n) ∈ O(max(f (n), g(n))) ⇒ ∃c∃n0 ∀n ≥ n0 h(n) ≤ c max(f (n), g(n)),
donc h(n) ≤ c(f (n) + g(n)) et donc h(n) ∈ O(f (n) + g(n))

5
— ⇐ : h(n) ∈ O(f (n) + g(n)) ⇒ ∃c∃n0 ∀n ≥ n0 h(n) ≤ c(f (n) + g(n)), donc
h(n) ≤ 2c(max(f (n), g(n))) et donc h(n) ∈ O(max(f (n), g(n)))

Exercice 3 Analyse de complexité

Question 7

— Meilleur des cas : Θ(1) si T [⌊ n+1


2 ⌋] = x
— Pire des cas :
1. Le code à l’intérieur de la boucle est en Θ(1) ; Le code à l’extérieur
de la boucle est en O(1) ; il suffit de compter le nombre d’itérations
2. La condition d’arrêt est i < j et j − i est divisé par 2 à chaque
itération, donc Θ(log n)

Question 8 Dans les deux cas, on peut remarquer que l’instruction la plus souvent
exécutée (terme dominant) est “r ← r + 1” avec r initialisé à 0 et retourné
par l’algorithme. Donc la complexité de ces algorithmes est du même ordre
de grandeur que la valeur retournée.
— L’algorithme f1 retourne ni=1 nj=i+1 1 = ni=1 (n − i) = n2 − ni=1 i =
P P P P

n2 − 21 n(n + 1) = 12 n(n − 1) : la somme des n − 1 premiers entiers positifs


— L’algorithme f2 passe ⌈log2 n⌉ fois dans la boucle puisque i est divisé par
2 à chaque itération. La valeur retournée est donc r = ⌈log2 n⌉.

Question 9 Le nombre d’instructions est égal à :


Pn−1 Pn P
j

i=1 j=i+1 k=1 Θ(1)
Pn−1 Pn 
= i=1 j=i+1 j
Pn−1  1 1

= i=1 2 n(n + 1) − 2 i(i + 1)
Pn−1 1  
1
= 2 (n − 1)n(n + 1) − i=1 2 i(i + 1)
1 1
= 2 (n − 1)n(n + 1) − 6 (n − 1)n(n + 1)
1
= 3 (n − 1)n(n + 1)

6
7
3 Complexité d’algorithmes récursifs
Exercice 1 Algorithmes recursifs
Question 1 Pour les deux fonctions rec1 et rec2, nous allons utiliser T1 (x) (res-
pectivement T2 (x)) pour représenter la complexité de rec1(x) (respectivement
rec2(x))
(1.a) rec1 (
Θ(1) si n = 1
T1 (x) =
T1 (x − 1) + Θ(1) sinon
Pour appliquer la méthode par substitution, il faut avoir une intuition
sur la forme de récurrence. Une façon simple de travailler l’intuition est
de construire T(x) de manière ascendante (en supposant que Θ(1) = 1 ).
C’est à dire :
— T1 (1) = Θ(1) = 1
— T1 (2) = T1 (1) + Θ(1) = 1 + 1 = 2
— T1 (3) = T1 (2) + Θ(1) = 2 + 1 = 3
— T1 (4) = T1 (3) + Θ(1) = 3 + 1 = 4
— ...
— T1 (x) = x
Donc à priori T1 (x) ∈ Θ(x). On va démontrer ce résultat. On prouve
T1 (x) ∈ Ω(x) (puis de manière similaire T1 (x) ∈ O(x))
On utilise le principe de récurrence (induction) pour montrer qu’il existe
c > 0 tel que ∀x ≥ 1, T1 (x) ≥ cx. On vérifie pour x = 1 en posant
T1 (1) = c1 :

T1 (1) = c1 ≥ c × 1
c1 ≥ c

Donc la constante c qu’on cherche doit satisfaire la condition c ≤ c1 .


On suppose T1 (i) ≥ c × i vrai pour 1 ≤ i ≤ x − 1 et on montre que
T1 (x) ≥ cx.

T1 (x) = T (x − 1) + c2
≥ c(x − 1) + c2
= cx − c + c2
≥ cx

8
À la dernière étape nous avons supposé que c ≤ c2
Donc par récurrence on a ∃c ∈ [c1 , c2 ], tel que T1 (x) ≥ cx. Donc T1 (x) ∈
Ω(x). De la même façon on montre que T1 (x) ∈ O(x). Par conséquent,
T1 (x) ∈ Θ(x).
(1.b) rec2 (
Θ(1) si x = 1
T2 (x) =
2T2 (x − 1) + Θ(1) sinon

Pour trouver une intuition sur la forme de T2 (x), on peut appliquer une
approche ascendante en supposant que Θ(1) = 1 :
— T2 (1) = 1
— T2 (2) = 2T2 (1) + 1 = 2 × 1 + 1 = 2 + 1 = 21 + 20
— T2 (3) = 2T2 (2) + 1 = 2 × (21 + 20 ) + 1 = 22 + 21 + 20
— T2 (4) = 2T2 (2) + 1 = 2 × (22 + 21 + 20 ) + 1 = 23 + 22 + 21 + 20
— ...
— T2 (x) = 2x−1 + 2x−2 . . . + 20
Donc à priori T2 (x) appartient à Θ(2x ). Pour montrer le résultat, on
prouve que T2 (x) ∈ Ω(2x ) (et T2 (x) ∈ O(2x )). On utilise le raisonnement
par récurrence pour montrer qu’il existe un c > 0 tel que T2 (x) ≥ c2x .
On vérifie pour x = 1 en posant Θ(1) = 1 :

T2 (1) = 1 ≥ c21
1
≥ c
2
Donc la constante c doit satisfaire 12 ≥ c.
On suppose T2 (i) ≥ c2i vrai pour 1 ≤ i ≤ x − 1 et on substitue :

T2 (x) = 2T2 (x − 1) + 1
≥ 2c2x−1 + 1
≥ (2c2x )/2 + 1
≥ c2x + 1
≥ c2x

Donc il suffit de prendre une constante 0 < c ≤ 21 . Par conséquence,


T2 (x) ∈ Ω(2x ). De manière similaire, on montre que T2 (x) ∈ O(2x ). Donc
T2 (x) ∈ Θ(2x ).

9
Question 2

(2.a) la taille de la donnée est Θ(log(x))


(2.b) expo1 ∈ Θ(x)
(2.c) Soit p la taille de la donnée (Θ(log(x))). Puisque expo1 ∈ Θ(x), alors
expo1 ∈ Θ(2p )
(2.d) Expression récursive :
(
Θ(1) si x = 1
T (x) =
T (x/2) + Θ(1) si x > 1

On utilise le principe de récurrence pour montrer que expo2 ∈ O(log x).


On vérifie pour T = 2 en posant Θ(1) = 1 : :

T (x/2) + 1 = 2 ≤ c log 2
2 ≤ c

On suppose T (i) ≤ c(log i) vrai pour 2 ≤ i ≤ x − 1 et on substitue :

T (x) = T (x/2) + 1
≤ c log(x/2) + 1
≤ c log(x/2) + log(2)
≤ c log(x/2) + c log(2)
≤ c log(2x/2)
≤ c log(x)

Donc vrai en prenant c ≥ 2.


(2.e) Similaire à la réponse précédente, on peut montrer que expo2 ∈ Ω(log x).
Donc expo2 ∈ Θ(log x). Puisque la taille de la donnée p ∈ Θ(log x), alors
expo2 ∈ Θ(p).
(2.f) expo2 est plus efficace (mais n’est correct que pour x pairs)

Question 3

(3.a) — expo2 :
T (x) = T (x/2) + x0
On a a = 1, b = 2, d = 0 et donc logb (a) = d : expo2 ∈ Θ(log x)

10
— expo3 :
T (x) = 2T (x/2) + x0
On a a = 2, b = 2, d = 0 et donc logb (a) > d : expo2 ∈ Θ(x)
(3.b) Logiquement équivalents, mais expo2 est plus efficace

Question 4

(4.a) y ∗ expo4(y, x − 1)
(4.b) Il faut remarquer que si x est impair, alors cette ligne coûte Θ(1) et expo4
est appelé avec x pair, donc :

Θ(1)

 si x = 1
T (x) = T (x/2) + Θ(1) si x est pair

T ((x − 1)/2) + Θ(1)

sinon
Le troisième cas est donc asymptotiquement équivalent au deuxième cas,
donc la démonstration utilisée pour expo2 fonctionne.

Exercice 2 Nombre de Catalan.


Question 5 Chemins de (0, 0) vers (n, n) monotones (non-decroissants selon x et
y) et tels que y ≤ x (ne croisent jamais la diagonale y = x). On appellera un
tel chemin sous-diagonal.

Question 6

— Ci et Cn−i−1 sont mononote (trivial).

— Ci va de (1, 0) à (i + 1, i), puisqu’il comporte (i − 1) ‘↑’ et (i − 1) ‘→’.

— Donc Cn−i−1 va de (i + 1, i + 1) à (n, n) sans croiser la diagonale.

11
— Supposons que Ci croise la diagonale sur la grille (1, 0) − (i + 1, i), c’est
à dire atteind la coordonnée j, j pour 1 ≤ j ≤ i. Alors le ‘↑’ qui atteind
(j, j) est précédé par j ‘→’ et j − 1 ‘↑’. Mais dans ce cas, i n’est pas le
plus petit entier tel que la proposition est vraie.

Question 7 Pour tout i de 0 à n − 1, il y a Ci possibilités pour ci et Cn−i−1


possibilités pour cn−i−1 . Ces choix sont indépendents, donc

n−1
X
Cn = Ci Cn−i−1
i=0

Question 8(8.a) Il y a autant de chemin monotone que combinaisons de n positions


dans une séquence de taille 2n qui vont correspondrent aux ‘↑’ (le reste
contriendra des ‘→’) c’est à dire :
!
2n
n

(8.b) Lorsque c atteind i, i + 1, il reste n − i ‘→’ et n − i − 1 ‘↑’, donc f (c)


contient au total n − 1 ‘→’ et n + 1 ‘↑’.
(8.c) f −1 (c) monotone : trivial. Supposons que f −1 (c) soit sous-diagonal, alors
par définition f −1 (c) = c et donc c n’atteind pas (n − 1, n + 1).
(8.d) Puisque f est une bijection, il y a le même nombre de chemins monotones
non sous-diagonaux que de chemin monotones de (0, 0) vers (n − 1, n + 1),
c’est à dire : !
2n
n+1
On a donc :
! ! !
2n 2n (2n)! (2n)! (2n)! n (2n)! 1 2n
Cn = − = − = − =
n n+1 n!n! (n − 1)!(n + 1)! n!n! n + 1 n!n! n+1 n

(8.e) ...

Question 9 √
n3/2 π
lim Cn =1
n→∞ 4n

12
Donc pour tout ϵ > 0 il existe nϵ tel que
3/2 √
nϵ π
Cnϵ n
≤1+ϵ
4 ϵ

1 + ϵ 4nϵ
Cnϵ ≤ √
π nϵ3/2
(1+ϵ)
Choisissons n’importe quelle valeur pour ϵ > 0 et posons c = √
π
et n0 = nϵ ,
on a  n 
4
Cn ∈ O
n3/2
Pour tout ϵ > 0 il existe nϵ tel que
3/2 √
nϵ π
Cnϵ ≥1−ϵ
4nϵ
1 − ϵ 4nϵ
Cnϵ ≥ √
π nϵ3/2
(1−ϵ)
Choisissons n’importe quelle valeur pour 1 > ϵ > 0 et posons c = √
π
et
n0 = nϵ , on a  n 
4
Cn ∈ Ω
n3/2

Question 10 Il y a autant de mots de longueur n dans Σ que de chemins sous-


diagonaux  une grille d’ordre n (‘→’ devient ‘(’ et ‘↑’ devient ‘)’), c’est à
 n dans
dire Θ n43/2 .
L’espace mémoire requis pour coder une donnée x de ce type est donc :

4n
 
|x| ∈ Θ(log2 )
n3/2
On a :

4n 3
 
log2 = 2n − log2 n
n3/2 2
et donc :

|x| ∈ Θ(n)

13
4 Programmation Dynamique
Exercice 1 Suite de Fibonacci

Question 1

(1.a) Il y a des redondances dans les appels récursifs comme le montre l’arbre
suivant (par exemple F(n-2) est appelé plusieurs fois) :
F(n)

F(n-1) F(n-2)

F(n-2) F(n-3) F(n-3) F(n-4)

... ... ... ... ... ... ... ...


1 Algorithme : Fibonacci(n)
Données : un entier n
Résultat : un entier qui vaut F(n)
2 début
3 F : tableaux de n entier;
(1.b) 4 F [0] ← 0 ;
5 F [1] ← 1 ;
6 pour i ∈ [2 . . . n] faire
7 F [i] ← F [i − 1] + F [i − 2]
8 retourner F [n];

(1.c) Il suffit de donner le tableau :


0 0
1 1
2 1
3 2
4 3
5 5
6 8
7 13
8 21
9 34
10 55

14
Exercice 2 Sacs à dos

Question 2

(2.a) F (n, W ) = max(F (n − 1, W ), F (n − 1, W − wn ) + vn )


(2.b) il faut donner l’arbre d’appels récursif :
F (n, W )

F (n − 1, W ) F (n − 1, W − wn )

F (n − 2, W ) F (n − 2, W − wn−1 ) F (n − 2, W − wn ) F (n − 2, W − wn − wn−1 )

... ... ... ... ... ... ... ...


On remarque que pour chaque niveau (horizontal) de l’arbre, il se peut
qu’il y a des appels redondants. Par exemple, si W − wn = W − wn−1 ,
alors F (n − 2, W − wn ) est identique à F (n − 2, W − wn−1 ). D’où l’intérêt
de la programmation dynamique.
(2.c) L’algorithme :

15
1 Algorithme : Knapsack(n, W, w1 , . . . , wn , v1 , . . . , vn ))
Données : n, W, w1 , . . . , wn , v1 , . . . , vn )
Résultat : F(n,W)
2 début
3 F : matrice de taille n + 1 × W + 1 ;
4 pour j ∈ [0 . . . W ] faire
5 F [0][j] ← 0
6 pour i ∈ [1 . . . n] faire
7 pour j ∈ [0 . . . W ] faire
8 si j − wi < 0 alors
9 F [i][j] ← F [i − 1][j]
10 sinon
11 F [i][j] ← max(F [i − 1][j], F [i − 1][j − wi ] + vi )

12 retourner F [n][W ];

(2.d) Il suffit de remplir la matrice F . Chaque ligne représente les i ∈ [0, n] et


chaque colonne représente les j ∈ [0, W ]. Pour P(3, 10, 7, 2, 3, 5, 11, 6)
n W =0 W =1 W =2 W =3 W =4 W =5 W =6 W =7 W =8 W =9 W = 10
0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 5 5 5 5
2 0 0 11 11 11 11 11 11 11 16 16
3 0 0 11 11 11 17 17 17 17 17 17

La question 1 du TD 7 étudie la classe de complexité de la version de décision du


problème.

16
5 Algorithmes gloutons et matroïdes
Exercice 1 Problème de bipartition

Question 1

(1.a) Exemples d’application :


— En biologie : classification des plantes et des animaux .
— Évaluation du risque sismique : regroupement des épicentres sismiques
observés pour identifier les zones dangereuses ;
— Clustering binaire : dans le domaine médical par exemple, ça permet
de faire des analyse sur la présence d’une certaine maladie.
(1.b) Une idée possible est de trier toutes les distances entre pairs (x,y) par
ordre décroissant, puis essayer d’éviter les grandes distances, une par une.
(1.c) Un algorithme possible

17
1 Algorithme : ClusteringGlouton (E = {x1 , x2 , . . . xn }, d
Données : E = {x1 , x2 , . . . xn }, d
Résultat : (A, B) : 2-Partition
2 A←∅;
3 B←∅;
4 F ← T rier{(xi , xj ) | 1 ≤ i < j ≤ n} par ordre décroissant sur la distance d(xi , xj );
5 i←1;
6 tant que |A ∪ B| ̸= n faire
7 (x, y) = F [i] ;
8 i←i+1 ;
9 si x ∈ A alors
10 si y ∈
/ A alors
11 B ← B ∪ {y}

12 sinon
13 si x ∈ B alors
14 si y ∈
/ B alors
15 A ← A ∪ {y}

16 sinon
17 si y ∈ A alors
18 si x ∈
/ A alors
19 B ← B ∪ {x}

20 sinon
21 si y ∈ B alors
22 si x ∈
/ B alors
23 A ← A ∪ {x}

24 sinon
25 % On va séparer x et y. Il y a deux choix possibles : ajouter x à A et y à B ou
ajouter x à B et y à A. On évalue d’abord le cout de chaque choix et on évite le
pire. ;
26 coutxA ← max(d(a, b) | (a, b) ∈ A ∪ {x} × A ∪ {x}) ;
27 coutxB ← max(d(a, b) | (a, b) ∈ B ∪ {x} × B ∪ {x}) ;
28 coutyA ← max(d(a, b) | (a, b) ∈ A ∪ {y} × A ∪ {y}) ;
29 coutyB ← max(d(a, b) | (a, b) ∈ B ∪ {y} × B ∪ {y}) ;
30 % on calcule le cout quand on ajoute x à A et y à B
cout1 ← max{coutxA, coutyB}
31 % on calcule le cout quand on ajoute x à B et y à A
cout2 ← max{coutxB, coutyA}
32 si cout1 > cout2 alors
33 A ← A ∪ {y} ;
34 B ← B ∪ {x}
35 sinon
36 A ← A ∪ {x} ;
37 B ← B ∪ {y}

38 retourner (A,B) ;

Complexité : Avec n éléments, il y a m = n(n−1)


2 paires possibles. Donc la
complexité de l’algorithme proposé est O(mlog(m) + mn) = O(n3 ) (car
m ∈ Θ(n2 )). Le premier terme de la complexité représente la complexité
du tri effectué au début de l’algorithme. Pour le reste, puisqu’on traite une
paire à chaque itération, alors le pire des cas correspond à m itérations.
Pour chaque itération, le pire des cas correspond au dernier tratement
ou on doit calculer coutxA, coutxB, coutyA, coutyB. Ce calcule demande

18
O(n) car A et B contiennent au plus n éléments.

Exercice 2 Problème d’ordonnancement de tâches unitaires sur une ressource

Question 2(2.a) Par exemple : Organisation des séances de TDs à l’INSA pour
une seule salle. La salle est la ressource. Une séance de TD est une tâche
(qui dure une unité de temps 1h15). Chaque séance peut avoir une date
d’échéance (par exemple un tel TD doit être effectué avant 12h15). On
cherche à maximiser le nombre de séances effectuées dans une salle tout
en respectant les échéances.
Autre exemple similaire : la réservation de salle à la bibliothèque de
l’INSA. Une salle est une ressource. Une demande de réservation est une
tache qui est associé à une date d’échéance. Pour une salle, on veut maxi-
miser le nombre de demandes satisfaites.
Autre exemple est le cas d’ordonnancement de tâches unitaires pour un
processeur.
(2.b) Pour la première instance :
F ←∅
L ← [a1, a4, a3, a2]

F ← {a1}
–> valide
F ← {a1, a4}
–> valide
F ← {a1, a4, a3}
–> valide
{a1, a4, a4}
–> n’est pas valide
Retourner F ← {a1, a4, a3}
(2.c) Oui par exemple quand deux taches ont la même priorité et la même date
d’échéance.
(2.d) Il faut montrer que :
— Si un exemple de taches est valide alors en supprimant une tache il
reste valide (héréditaire)

19
— Si A et B sont deux ensembles de taches valides tel que |A| < |B| alors
il existe une tache t dans B \ A tel que A ∪ {t} est valide (échange)
(2.e) — La fonction du poids sur le matroïde est la fonction de priorité.
— E est héréditaire –> évident
— Échange : Soit A et B deux exemples de taches valides tel que A =
{a1 , . . . an }, B = {b1 , . . . bm } et n < m. Prenons la tache bk de B qui
n’appartient pas à A avec la plus grande date d’échéance. Ajouter bk
à A donne un ensemble valide.
(2.f) Il suffit de faire le tri des éléments de F à chaque fois par ordre croissant
sur les dates d’échéance (Θ(nlog(n))). Ceci donne une complexité totale
de O(n2 log(n)) de l’algorithme.
On peut améliorer cette méthode en gardant les taches de F dans une liste
ordonnée par ordre croissant par rapport aux dates d’échéances. Pour
chaque élément à tester, construire la nouvelle liste ordonnée est linéaire
car il suffit de faire un parcours à partir de la fin de la liste jusqu’à la
position du nouvel élément. Une fois l’insertion est faite, il suffit de faire
le test de validité en O(n) et donc la complexité de l’algorithme est O(n2 ).

20
6 Structures de données
Exercice 1 Structure de données

Question 1 [1, 2, 5, 4, 3, 9, 6, 10, 7, 8]

Question 2 On peut utiliser une table de hâchage pour les paires (x, y) (la clé est
la concaténation de x et y) ; un ABR pour lister les émetteurs et un autre
pour lister les récepteurs.

21
7 Classes de complexité
Pas au programme (sauf montrer qu’un problème est dans P ou dans NP)
Exercice 1 P et NP

Question 1 QCM :
— P ⊆ NP ? : Oui
— P ⊊ NP ? : On ne sait pas
— Si P = NP alors P = NP = NP-Complet ? : Oui
— P ⊊ NP alors NP \ NP-Complet = P ? : Oui
— P ⊊ NP alors NP \ P = NP-Complet ? : Oui
— P ⊊ NP alors P ⊊ NP-Complet ? : Non
— P ⊊ EXP ? : Oui
— NP ⊊ EXP ? : Oui
— NP ⊊ NP-Complet ? : On ne sait pas
— Si P = NP alors P = NP = NP-Complet ? : Oui
— Si P = NP alors NP-Complet \ P = ∅ ? : Oui
— NP = EXP ? : Non
— Si A ∈ Θ(2n ) est un algorithme pour un problème Pb alors Pb ∈ EXP ? :
Oui
— Si A ∈ Θ(2n ) est un algorithme pour un problème Pb alors Pb ∈ NP ? :
on ne sait pas
— Si A ∈ Θ(2n ) est un algorithme pour un problème Pb alors Pb ∈ P ? : on
ne sait pas

Question 2

— Sac-à-Dos ∈ NP :
— Certificat : le sous-ensemble S d’objets (espace mémoire en Θ(n) en
utilisant un tableau de booléens)
— Vérification en O(n log W ) : il faut calculer la somme des vi et la
somme des wi , la taille de la donnée est en Θ(n log W ), l’algorithme
est donc linéaire dans la taille de la donnée

22
Question 3 ProgDyn ∈ Θ(nW ). Ce n’est pas une preuve que Sac-à-Dos ∈ P
puisque qu’il faut un algorithme polynômial dans la taille de la donnée. Ici la
donnée x est telle que |x| ∈ Θ(n log W ). Supposons que n ≃ log W , alors on
a |x| ∈ Θ(log W ) et ProgDyn ∈ Θ(W log W ), donc on a ProgDyn ∈ Ω(|x|2|x| )

23
8 Recherche Arborescente
Exercice 1 Recherche arborescente

Question 1 ...

Question 2 ...

Question 3 Montrez que ces 3 problèmes sont dans la classe NP.


Solution : montrez que l’on a un algorithme de complexité polynomial pour
vérifier une solution (à chacun de ces problèmes considérés en version pro-
blème de décision)

Exercice 2 Récurrence de Zykov : coloration de graphes


Question 4 Le graphe de la figure ?? (2) est-il 3-colorable ? Pourquoi ?
Solution : non car il contient une clique de taille 4.

Question 5 Déduisez une borne inférieure du nombre chromatique χ(G) d’un


graphe G quelconque.
Solution : χ(G) ≥ taille clique max(G). On a obtenu une borne optimiste (ici
borne inférieure) pour le problème de coloration des sommets d’un graphe.
Quelle est la valeur de cette borne pour le graphe de la figure ?? (3a) ?
Solution : il y a des cliques de taille 2. Il faut au moins 2 couleurs pour ce
graphe.

Question 6 Essayez de trouver une 3-coloration pour le graphe de la figure ??


(3a).
Solution : n’y passez pas trop de temps ... (il n’y en n’a pas)

24
On veut concevoir un algorithme pour la coloration de graphe basé sur la récurrence
de Zykov.
Question 7 Montrez que l’équation suivante est correcte pour tout graphe G =
(S, A), et toute paire de sommets distincts v, w ∈ S tels que (v, w) ̸∈ A :

χ(G) = min(χ(G + (v, w)), χ(G/(v, w)))

Solution : pour un graphe G pouvant être coloré avec χ(G) couleurs et conte-
nant 2 sommets u et v non reliés par une arête. Il y a deux possibilités de
couleur pour ces sommets :
— soit u et v sont de la même couleur : ces deux sommets peuvent être
fusionnés et produire le graphe G/(v, w)
— soit u et v sont de couleurs différentes : ces deux sommets peuvent être
séparés par une arête et produire le graphe G + (v, w)
Donc χ(G) correspond au minimum de couleurs permettant de colorer ces
deux graphes.

Question 8 Donnez un espace de recherche rendu possible grâce à cette équation,


et l’arbre de recherche associé. Comment reconnait-on une feuille ?
Solution : On peut définir l’espace de recherche comme l’ensemble de tous
les graphes obtenus à travers des séquences de contraction et de séparation.
A chaque étape : on choisit une non arête et on arbitre : soit les sommets
de cette non arête ont la même couleur et on produit un nouveau graphe en
fusionnant les deux sommets (contraction) ; soit les deux sommets ont une
couleur différente et on produit un nouveau graphe en ajoutant une arête
(séparation). Une feuille correspond à une clique car sa taille est égale au
nombre chromatique de la solution correspondante.

Dégénérescence
Question 9 Soit un graphe G, et un sommet k-dégénéré v de ce graphe. Montrez
que G est k + 1-colorable si et seulement si G \ v est k + 1-colorable.
Solution :
— G est k + 1-colorable → G \ v est k + 1-colorable : (trivial) : si le graphe
initial est k + 1-colorable il reste k + 1-colorable quand on lui retire un
sommet
— G \ v est k + 1-colorable → G est k + 1-colorable : le graphe G \ v est
k +1-colorable et on lui ajoute un sommet v ayant au plus k voisin, il faut
au pire k + 1 couleurs pour ce sommet v et ses voisins. Donc le graphe
avec v est k + 1-colorable.

25
Question 10 Supprimer les sommets 3-dégénérés du graphe de la figure ?? (3a),
continuer jusqu’à ce que ce ne soit plus possible.
Solution : on peut retirer tous les sommets et obtenir un graphe vide.
Que peut-on en déduire sur la colorabilité du graphe de la figure ?? (3a) ?
Solution : on a obtenu une borne (supérieure) sur le nombre de couleurs
possibles pour ce graphe

Question 11 Quelle est la règle d’élagage induite par la borne supérieure calculée
dans la question précédente et la borne inférieure définie dans la question 8 ?
Solution : si taille clique max = valeur dégénéresence + 1 alors stopper la
recherche arborescence.

Question 12 Séparez les sommets v2 et u2 dans le graphe de la figure ?? (3c),


est-ce que le graphe résultant est 3-colorable ?
Solution : quand on sépare les sommets v2 et u2 on fait apparaitre un clique de
taille 3 (v2 , u2 et le sommet (w, v)) et en considérant le sommet supplémentaire
u3 il y a presque une clique max de taille 4 : il manque une seule arête entre
u2 et u3 .
Une clique de taille 4 ne permet pas d’améliorer une solution déjà connue
avec la propriété de dégénérescence. On va donc interdire la formation de ces
cliques en considérant que les sommets u2 et u3 doivent être fusionnés.
Même question pour les sommets u2 et u5 dans le graphe de la figure ?? (3b).
Déduisez-en une nouvelle règle d’élagage.
Solution : fusionner deux sommets permettant d’éviter une clique de taille 4
(pour ce graphe)

Question 13 Explorer complètement l’arbre de recherche dont la racine est le


branchement “w = v1 ou w ̸= v1 ” en appliquant les règles d’élagage vues
précédemment.

26
9 Annales
Exercice 1 Sous-séquence maximale
Question 1 Θ(n)

Question 2
1 Algorithme : MaxSousSéquenceq ((L))
Données : un tableau L avec éléments Pedans {−1, 1}
Résultat : les entiers s et e tels que i=s
L[i] est maximal
2 s ← 1;
3 e ← 1;
4 m ← L[1];
5 pour chaque x allant de 1 à n faire
6 z ← 0;
7 pour chaque y allant de x à n faire
8 z ← z + L[y];
9 si z > m alors
10 s ← x;
11 e ← y;
12 m ← z;

Question 3

(3.a) (
O(1) si n ≤ 1
T (n) =
2T (n/2) + Θ(n) sinon

(3.b) a = 2, b = 2, d = 1 : T (n) ∈ Θ(n log n)


(3.c) (preuve pour T (n) ∈ O(n log n))
En substituant des fonctions concrètes aux ordres de grandeur, la fonction
récursive qui donne la complexité du pire appel récursif est

T (n) = cn log n

On fait l’hypothèse de récurrence

T (n) ≤ cn log n

L’hypothèse est vraie aux limites :


— pour n = 2, on a T (2) = T (⌈2/2⌉) + 1 = 2 ≤ c2 log 2 pour c ≥ 1 ;

27
— pour n = 3, on a T (3) = T (⌈3/2⌉) + 1 = 3 ≤ c3 log 3 pour c ≥
3/(log 3) ;
On montre que si l’hypothèse est vraie pour n−k pour tout 1 ≤ k ≤ (n−2)
alors elle reste vraie pour n
Puisque T (n−k) ≤ c(n−k) log(n−k), alors T (⌈n/2⌉) ≤ c(⌈n/2⌉) log(⌈n/2⌉)

T (n) = T (⌈n/2⌉) + n
≤ c(⌈n/2⌉) log(⌈n/2⌉) + n
c
= n(log(n) − log(2)) + n
2
c
= n log(n)
2

Question 4

(4.a) Θ(n)
(4.b) Oui
(4.c) MaxSousSéquenceq :70 heures ; MaxSousSéquencer :10 secondes ; MaxSousSéquencel :
0,5 secondes

28
Exercice 2 Plus courts chemins

Soit V = {1, . . . , n}. L’algorithme suivant calcule tous les plus courts chemins
depuis un sommet s ∈ V vers chaque sommet v ∈ V dans le graphe non-orienté
G = (V, E) où E est un ensemble de m arêtes, c’est à dire de m paires distinctes
de sommets de V . Le graphe est représenté par des listes de voisins : la liste N (v)
contient tous les voisins du sommet v, c’est à dire l’ensemble des sommets u tels
que {u, v} 1 ∈ E. Les arêtes sont valuées, et la “longueur” d’une arête L[{u, v}] est
accessible en temps constant.
Dans cet algorithme, toutes les opérations d’ajout, de suppression, d’affectation et
les additions seront considérées en temps constant (O(1)).
Les réponses des six premières questions sont à donner en ordre de grandeur
(Θ) en fonction de n et/ou de m. Si vous avez un doute, une réponse moins
précise utilisant Ω et/ou O rapportera plus de points qu’une réponse erronée en
Θ.
Notez que comprendre le fonctionnement de l’algorithme n’est pas absolument
nécessaire pour répondre aux questions.

1 Algorithme : PlusCourtChemin
Données : Un ensemble de sommets V , des listes de voisinage N , une table de
distance L et un sommet s ∈ V
Résultat : un tableau dist, où ∀v ∈ {1, . . . , n}, dist[v] est la distance du plus court
chemin entre s et v dans le graphe
2 Q ← ∅;
3 pour chaque v ∈ V faire
4 dist[v] ← ∞;
5 ajouter v à Q;
6 dist[s] ← 0;
7 tant que Q n’est pas vide faire
8 u ← sommet de Q tel que dist[u] est minimal;
9 retirer u de Q;
10 pour chaque v dans la liste N (u) faire
11 l ← dist[u] + L[{u, v}];
12 si l < dist[v] alors
13 dist[v] ← l;

14 retourner dist;

Question 5 Θ(n).

1. ou {v, u} puisque le graphe n’est pas orienté

29
Question 6 Θ(n) fois (le sommet u est supprimé).

Question 7 l’arête u, v peut être lue O(2) fois : pour v ∈ N (u) et pour u ∈ N (v).

Question 8 Θ(m) fois.

Question 9 Θ(n2 ) (puisque m ≤ n2 ).

Question 10 Θ(m log n) (on considère que le graphe est connexe et donc n ≤
m + 1).

Question 11 Oui.

Question 12 n!

30
Exercice 3 Recherche arborescente

Question 13 ...

Question 14 ...

Question 15 Montrez que ces 3 problèmes sont dans la classe NP.


Solution : montrez que l’on a un algorithme de complexité polynomial pour
vérifier une solution (à chacun de ces problèmes considérés en version pro-
blème de décision)

31
Exercice 4 Vote à la majorité absolue
Question 16

(16.a) Avec m constant : Θ(n) × Θ(1) = Θ(n)


(16.b) Avec m variable : Θ(n) × Θ(log m) = Θ(n log m)

Question 17 Θ(n2 ).

Question 18

(18.a) complexité en temps : Θ(n + m) ; complexité en espace : Θ(m) (ou


Θ(m log n) pour être plus précis)
(18.b) Si m ∈ Ω(n2 ) et n2 ̸∈ O(m)

Question 19

(19.a) Le seul élément non trivial de la preuve est que lorsqu’on sépare les vo-
tants en deux groupes, l’élément majoritaire doit forcément être majo-
ritaire dans au moins un des deux groupes. Donc on n’a pas besoin de
compter le nombre de voix des autres candidats.
(19.b) 



 Θ(1) si n ≤ 1
T (n) =


2T ( n2 ) + Θ(n) sinon

(19.c) Θ(n log n).

Question 20

(20.a) complexité en temps : Θ(n) ; complexité en espace : Θ(1) ou Θ(log n +


log m) (selon si considère que compte et candidat sont des int (bornés)
ou non)

32
(20.b) l’algorithme Dépouillement est en Ω(n + m) et la taille |x| de la donnée
est en O(n log m). Soit m ≫ 2n . Dans ce cas, Dépouillement requiert
Ω(m) operations et |x| ∈ O(log m), donc Dépouillement requiert Ω(2|x| )
operations.
Donc il existe au moins un cas où la complexité de Dépouillement n’est
pas en O(|x|c ) (pour |x| la taille de la donnée et c une constante). Par
conséquence, Dépouillement ne peut pas être utilisé pour prouver que
ce problème est dans P.
Tous les autres algorithmes constituent des preuves valides que ce pro-
blème est dans P.
(20.c) Il suffit de vérifier que le candidat renvoyé par Boyer-Moore est bien
majoritaire, en comptant combien de votes il a reçu. Il est évident que
c’est possible en O(n) temps.

Question 21

(21.a) Par définition, un candidat x est majoritaire si et seulement si marge(x, n) >


0. b(n) implique que pour tout x ̸= candidat, marge(x, n) ≤ 0, donc seul
candidat (celui retourné par Boyer-Moore) peut être majoritaire. Par la
définition du problème, il existe un candidat majoritaire, donc il ne peut
s’agir que de candidat. (Notez que a(n) n’est pas utile pour cette preuve)
S: 1 1 1 3 3 2 2 3 3 3 2 3 3
compte 1 2 3 2 1 0 1 0 1 2 1 2 3
candidat 1 1 1 1 1 1 2 2 3 3 3 3 3
(21.b)
marge(1, i) 1 2 3 2 1 0 -1 -2 -3 -4 -5 -6 -7
marge(2, i) -1 -2 -3 -4 -5 -4 -3 -4 -5 -6 -5 -6 -7
marge(3, i) -1 -2 -3 -2 -1 -2 -3 -2 -1 0 -1 0 1
(21.c) Il faut aussi prouver que les invariants sont vrais dans la première itération
(a(1) et b(1)) et qu’ils se conservent (a(i) et b(i) impliquent a(i + 1) et
b(i + 1))

10 Bonus, preuve de conservation des invariants

— Invariant a(i) : marge(candidati , i) ≤ comptei

33
— Invariant b(i) : x ̸= candidati =⇒ marge(x, i) ≤ −comptei

si a(i) et b(i), alors a(i + 1) :


On note candidati la valeur de la variable candidat à la fin de l’itération i et
comptei la valeur de la variable compte à la fin de l’itération i.
Il y a deux cas :
1. S[i + 1] = candidati : Alors candidati+1 = candidati . De plus comptei+1 =
comptei + 1 et marge(candidati+1 , i + 1) = marge(candidati , i) + 1, et donc
a(i) =⇒ a(i + 1).
2. S[i + 1] ̸= candidati : On décompose encore en deux cas. Soit comptei > 0,
et dans ce cas on a encore candidati+1 = candidati . De plus comptei+1 =
comptei − 1 et marge(candidati+1 , i + 1) = marge(candidati , i) − 1, et donc
a(i) =⇒ a(i + 1) ; Soit comptei = 0 et dans ce cas candidati+1 ̸= candidati .
Il s’en suit que comptei+1 = 1 et par b(i) on a marge(candidati+1 , i) ≤ 0 et
donc marge(candidati+1 , i + 1) ≤ 1.

si a(i) et b(i), alors b(i + 1) :


Il y a deux cas :
1. candidati+1 = candidati et donc on a ∀x ̸= candidati+1 marge(x, i) ≤ −comptei :
On décompose encore en deux cas. Soit candidati+1 = S[i+1], alors marge(x, i + 1) =
marge(x, i) − 1 et comptei+1 = comptei + 1 donc b(i) =⇒ b(i + 1) ; Soit
candidati+1 ̸= S[i + 1], alors comptei+1 = comptei − 1 et marge(x, i + 1) ≤
marge(x, i) + 1 donc b(i) =⇒ b(i + 1).
2. candidati+1 ̸= candidati et donc comptei = 0. Puisque comptei = 0, avec a(i)
et b(i) on a ∀x ̸= candidati+1 marge(x, i) ≤ 0. De plus, ∀x ̸= candidati+1 marge(x, i + 1) =
marge(x, i − 1) et comptei+1 = 1, donc b(i) =⇒ b(i + 1).

34

Vous aimerez peut-être aussi