




























































































Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Ce document présente une série d'exercices et de questions portant sur les algorithmes et la complexité. Il couvre des sujets tels que la calculabilité, la complexité, la récursivité, la programmation dynamique, la programmation linéaire, les algorithmes d'approximation, les algorithmes paramétrés, les algorithmes probabilistes, etc. Le document est conçu pour aider les étudiants à approfondir leur compréhension de ces concepts et à développer leurs compétences en résolution de problèmes.
Typology: Lecture notes
1 / 111
This page cannot be seen from the preview
Don't miss anything!





























































































Ecole Centrale
CNRS et Université Paris Diderot [email protected]
Version 17 octobre 2017
Résumé Ce cours a pour objectif de donner aux élèves un aperçu de quelques unes des techniques modernes de conception et d’analyse d’algorithmes. Ainsi, tous les grands thèmes de l’algo- rithme seront abordés dans le cours : calculabilité, complexité, récursivité, programmation dynamique, programmation linéaire, algorithmes d’approximation, algorithmes paramétrés, algorithmes probabilistes, etc. A l’issue de ce cours, les élèves devraient être capables d’iden- tifier la ou les méthodes les plus appropriées pour la résolution des problèmes algorithmiques qu’ils pourront rencontrer dans leurs carrières. Il ne sera bien sur pas possible de rentrer dans les détails de toutes les thématiques abordées dans le cours, qui mériteraient chacune un cours à part entière. Toutefois, les ouvrages de référence qui seront indiqués durant le cours devraient permettre de satisfaire tous les élèves désirant en savoir plus sur tels ou tels thèmes du cours.
Ouvrages de référence
— Complexité algorithmique [11] — Techniques de conception et d’analyse d’algorithmes [3] — Algorithmes d’approximation [14] — Algorithmes paramétrés [5] — Algorithmes probabilistes [9] — Méthodes heuristiques [8] — Algorithmes parallèles [6] — Algorithmes distribués [1, 7, 12] — Algorithmes online [2]
Introduction
L’algorithmique est la discipline de l’informatique traitant de la conception et l’analyse d’al- gorithmes. A ce titre, l’algorithmique se concentre principalement sur des problèmes abstraits dont la résolution permet de mettre en évidence de grands principes pouvant ensuite être décli- nés pour la résolution de problèmes spécifiques issus d’applications pratiques. L’algorithmique se distingue de la programmation au sens où l’algorithmique permet de concevoir des algorithmes à un certain niveau d’abstraction, susceptibles ensuite d’être programmés dans n’importe quel language de programmation. La traduction d’un algorithme en programme nécessite néanmoins de tenir compte du language de programmation, de l’environnement d’exécution du programme, de ses entrées, de ses sorties, etc., toutes choses qui ne sont pas au centre des intérêts de l’al- gorithmique. L’exemple de l’algorithme PageRank, au cœur de nombreux moteurs de recherche, illustre la différence entre algorithmique et programmation. En effet, autant il est relativement aisé de comprendre les principes de base de PageRank, voire de décrire PageRank sous forme d’un algorithme relativement compact, autant le passage de la description algorithmique de PageRank à la conception d’un moteur de recherche nécessite un travail considérable.
Algorithmique Programmation Vérification
assistants de preuves
théorie des graphes combinatoire
logique
algèbre
Figure 1 – L’algorithmique au sein de la chaine de conception de logiciels
La figure 1 illustre la position de l’algorithmique au sein de la chaine de conception de logi- ciels. La conception et l’analyse d’algorithmes se nourri de résultats et de concepts à l’interface entre mathématique et informatique. Des concepts issus de l’algorithmique, il est possible de dé- river des programmes, soit manuellement, soit via l’utilisation d’outils tels que les assistants de preuves, ces derniers permettant à la fois de concevoir un programme et d’en générer une preuve de correction. Une fois le programme conçu, il convient ensuite de le vérifier, soit statiquement, soit à l’exécution.
L’algorithmique est donc essentielle à la conception de logiciels efficaces. Sans algorithmique, point de PageRank, et donc point de Google. Ce document effectue un survol des résultats algorithmiques les plus importants. Il débute par des rappels de calculabilité et de complexité, et se poursuit par la description de techniques de conception et d’analyse d’algorithmes. Il aborde les algorithmes d’approximation, les algorithmes paramétrés, et les algorithmes probabilistes.
1 Préambule : les graphes et PageRank de Google
Ce cours utilisera abondemment la notion de graphe, un des modèles les plus utilisés pour for- maliser les problèmes réels. Par exemple, Internet peut être vu comme un graphe connectant des routeurs, et le Web comme un graphe connectant des pages html. Les interactions moléculaires se modèlent également comme un graphe, tout comme les relations entre concepts linguistiques ou les relations entre les espèces dans la théorie de l’évolution, et caetera. On pourrait multiplier les exemples à l’infini.
Rappelons donc qu’un graphe G est défini comme une paire (V, E) où V est l’ensemble
— T est un arbre de n sommets ; — T est un graphe connexe sans cycle de n sommets ; — T est un graphe connexe de n sommets et n − 1 arêtes ; — T est un graphe sans cycle de n sommets et n − 1 arêtes. — T est un graphe sans sommet isolé (i.e., tout sommet est incident à au moins une arête) de n sommets et n − 1 arêtes. Le degré deg(u) d’un sommet u est le nombre d’arêtes incidentes à ce sommet. Ainsi, tous les sommets ont degré 2 dans un cycle. Un graphe dont tous les sommets ont même degré est dit régulier. Tous les cycles, ainsi que le graphe de Petersen sont donc réguliers. Notez également que, dans un graphe G = (V, E), on a
∑
u∈V
deg(u) = 2|E|
car chaque arête contribue de 1 aux degrés de ses deux extrémités. Il en découle que |E| ≤ n(n 2 −1) car chaque sommet a un degré au plus n − 1. (Dans ce cours, tous les graphes considérés sont simple, c’est-à-dire qu’il n’y a au plus qu’une arête entre deux sommets, et sans boucle, c’est-à- dire qu’il n’y a pas d’arête connectant un sommet à lui même). Un chemin est un arbre dont tous les sommets ont degré au plus 2. Un graphe connexe est donc un graphe tel que, pour toute paire de sommets s 6 = t, il existe un chemin P dans G d’extrémité s et t, c’est-à-dire
P = (v 0 , v 1 , v 2 ,... , vr)
où v 0 = s, vr = t, et {vi, vi+1} ∈ E(G) pour tout i = 0,... , r − 1. Un graphe pondéré est un graphe G = (V, E) tel que chaque arête e ∈ E à un poids ω(e) ≥ 0. Si ce poids est interprété comme une longueur ` alors la longueur de P est
r∑− 1
i=
`({vi, vi+1)}).
La distance dist(u, v) entre deux sommets s et t de G est la plus petite longueur d’un chemin entre s et t dans G. Dans un graphe non pondéré, on suppose la longueur de chaque arête égale à 1, et la distance entre deux sommets s et t est donc le nombre d’arêtes du plus court chemin d’extrémités s et t. Le diamètre d’un graphe G = (V, E) est D = maxu,v∈V dist(u, v).
Le cours ne nécessite pas de connaissances approfondies en théorie des graphes. Tout étudiant souhaitant en savoir plus sur cette théorie féconde est néanmoins invité à consulter [4].
Il existe plusieurs façons de coder un graphe G de n sommets. On peut le faire par sa matrice d’adjacence booléenne M de taille n × n. A cette fin, on numérote les sommets de 1 à n, et M [i, j] = 1 si et seulement si il existe une arête entre les sommets i et j (ou, dans le cas orienté, s’il existe un arc de i vers j). On peut aussi coder le même graphe G par ses listes d’adjacence Li, i = 1,... , n, où Li est la liste de tous les sommets voisins du sommets i. On peut enfin coder G par sa matrice d’incidence M. Pour un graphe de n sommet et m arêtes, cette matrice est une matrice booléenne n × m telle que M [i, j] = 1 si et seulement si le sommet i est incident à l’arête j. Ces codages sont équivalents à une réduction en temps polynomial près. Voici par exemple une réduction du codage en listes d’adjacence au codage en matrice d’adjacence.
Algorithme matrix2list(M ) : début n ← dimension(M ) pour i = 1 à n faire k ← 1 pour j = 1 à n faire si M [i, j] = 1 alors Li[k] ← j k ← k + 1 Li[k] ← ⊥ /* symbole de fin de liste */ retourner L = (L 1 , L 2 ,... , Ln) fin
Notations asymptotiques. Afin de discuter des avantages et inconvénients de ces deux co- dages de graphes, on rappelle que la notation f = O(g) indique qu’il existe c > 0 et x 0 tel que f (x) ≤ c · g(x) pour tout x ≥ x 0. De même, f = Ω(g) indique qu’il existe c > 0 et x 0 tel que f (x) ≥ c · g(x) pour tout x ≥ x 0 , et f = Θ(g) indique que f = O(g) et f = Ω(g).
Le codage d’un graphe par liste utilise une mémoire de Θ(m log n) bits pour un graphe de m arêtes, ce qui peut être significativement plus petit que l’espace Θ(n^2 ) bits nécessaire au codage par matrice d’adjacence, pour un graphe peu dense. Cependant vérifier si deux sommets sont voisins réclame de chercher dans une liste, ce qui peut être coûteux en temps (de l’ordre de la longueur de la liste), surtout si la liste n’est pas triée.
La matrice d’adjacence M d’un graphe fournit quantité d’informations sur ce graphe (cf. la théorie algébrique des graphes). En particulier, de simples manipulations matricielles permettent d’effectuer des opérations complexes sur les graphes et de déduire des propriétés de ces graphes. Par exemple, l’existence d’un chemin de longueur de i à j dans un graphe se traduit par l’existence d’une valeur positive à la position (i, j) de la matrice M. (Cette valeur est de fait égale au nombre de chemins de longueur ` entre i et j.)
Pagerank de Google. Les procédures mises en oeuvre par Google pour classer les pages web contenant les mots clés relatifs à une requête à ce système ne sont pas publiques. En revanche, on sait qu’elles sont bâties autour de l’algorithme Pagerank. Ce dernier cherche à simuler le comportement d’un surfeur du web passant au hasard de page en page. La probabilité pour ce surfeur de se retrouver sur une page spécifique est d’autant plus grande que cette page est référencée par un grand nombre de pages elles mêmes référencées par un grand nombre de pages, etc. Cette propriété est capturée par la notion de marche aléatoire dans un graphe, consistant à quitter le sommet courant par un arc incident choisi uniformément aléatoirement parmi les arcs sortants de ce sommet. Une telle marche correspond à un processus Markovien puisque la probabilité pt(i) que le surfeur soit en un sommet i au temps t ne dépend que de la position du surfer au temps précédent.
Plus spécifiquement, si M désigne la matrice d’adjacence du graphe, on définit la matrice de transition Q par Q = D−^1 M où D est la matrice diagonale définie par Di,i =
∑n j=1 Mi,j^. La matrice de transition n’est donc rien d’autre que la matrice d’adjacence normalisée par le degré de chaque sommet, de façon à ce que
∑n j=1 Qi,j^ = 1^ pour tout^ i^ = 1,... , n. Par définition de la
2 Calculabilité et complexité algorithmique
La calculabilité est le domaine scientifique traitant de la capacité de résoudre un problème algorithmiquement. La complexité est le domaine scientifique traitant de la difficulté des pro- blèmes, en les classant dans différentes classes définies selon différents critères d’efficacité (temps, mémoire, etc.), et en étudiant les relations entre ces classes. Cette partie du cours décrit les bases des théories de la calculabilité et de la complexité, ainsi que deux classes essentielles : p et np. D’autres classes de complexité seront introduites au fur et à mesure de l’avancée du cours.
Pour parler de la difficulté à calculer tel ou tel résultats ou à résoudre tel ou tel problème, il convient de se mettre d’accord sur ce que veut dire « calculer ». Alan Turing (1937) a défini une machine abstraite, appelée depuis machine de Turing, permettant de donner un sens précis à la notion de calcul.
Informellement, une machine de Turing est constituée d’un ruban (ou d’une bande) formé(e) d’un nombre infini de cases auxquels accède une tête de lecture et d’écriture. Intuitivement, le ruban modélise la mémoire d’un ordinateur, et la tête de lecture modélise le processeur. Initialement, la tête de lecture est supposée positionnée en face du premier caractère du ruban infini dans un sens. Les données d’entrée x de la machine sont codées sur les |x| premières caractères de la bande, où |x| dénote le nombre de caractères utilisés pour coder la donnée x. A chaque étape de calcul, le symbole sous la tête de lecture est lu. La machine change alors potentiellement d’état, et écrit un nouveau symbole sur la bande en lieu et place du symbole lu. La tête de lecture se déplace ensuite d’un symbole vers la droite ou vers la gauche. Le nouvel état de la machine, le symbole écrit, et le déplacement dépendent du symbole lu et de l’état courant de la machine lorsque le symbole est lu. Les données de la machine sont décrites par une suite de symboles initialement écrits en début de ruban. Lorsque la machine entre dans un état final spécifié, elle s’arrête, et le résultat du calcul est l’ensemble des symboles écrits sur la bande. Je vous invite à taper « the lego Turing machine Youtube » dans Google pour observer une machine de Turing en action!
2.1.1 Definition
La définition formelle d’une machine de Turing est la suivante (voir aussi la figure 5) :
Definition 1 Une machine de Turing est un quintuplet M = (Q, Γ, δ, q 0 , F ) où Q dénote l’en- semble fini des états de la machine, Γ l’ensemble fini de symboles pouvant être écrit sur la bande de la machine (incluant le symbole « blanc » pouvant apparaître infiniment sur la bande de la machine), δ : Q × Γ → Q × Γ × {− 1 , +1} est la fonction de transition, q 0 est l’état initial, et F ⊆ Q est l’ensemble des états finaux.
Exercice 1 Décrire une machine de Turing M qui, étant donné un entier x ∈ N quelconque écrit sur le ruban, décide si x est pair ou non. (Dans le premier cas, M doit terminer dans l’état « oui », et, dans le second cas, M doit terminer dans l’état « non »).
Il convient de noter que la machine de Turing n’est pas la seule façon de donner une définition formelle au calcul. Ainsi, le λ-calcul, introduit par Alonzo Church dans les années 30 permet
0 1 1 0 0 1 0 01 1 0 1 1
Tête de lecture
Ruban
Données
état q
Figure 5 – Une machine de Turing. Dans cet exemple, il est indiqué que le ruban contient initialement la donnée 01100. La tête de lecture se situe en position 11 du ruban, et lit 0. Si l’état de la machine est dans l’état q ∈ Q, elle calcule le triplet (q′, x, d) = δ(q, 0). Cela correspond au fait que la machine passe dans l’état q′, écrit x sur le ruban en position courante (c’est-à-dire la position 11), et se déplace à droite (si d = +1) ou à gauche (si d = − 1 ).
aussi de formaliser la notion de calcul, tout comme les fonctions récursives dues à Kleene, ou les automates cellulaires. La machine de Turing peut paraître limitée et primitive. Elle se révèle au contraire d’une grande richesse, certes difficile à percevoir lorsque l’on est confronté à cet objet pour la première fois. En fait, l’hypothèse, ou thèse, de Church-Turing, exprimée dans les années 40, conjecture que la machine de Turing capture exactement la notion de calcul.
Thèse de Church-Turing : les machines de Turing formalisent correctement la notion de méthode effective de calcul.
Informellement, cette thèse énonce que tout calcul fondé sur une méthode effective peut être effectué par une machine de Turing. La notion de thèse fait ici référence au fait que l’adjectif « effective » est vague. Ce qu’elle prétend est que, quelque soit la façon d’imaginer un calcul, ce dernier pourra être effectué par une machine de Turing. Depuis plus de 70 ans, cette thèse n’a pas été remis en cause. Notez que la thèse de Church-Turing reste vraie par exemple pour des ordinateurs quantiques. Ces derniers (encore hypothétiques physiquement à grande échelle, mais effectifs en terme de modèle de calcul) sont plus rapides que les machines de Turing, mais il ne calculent pas plus de choses que ce que peuvent calculer ces dernières 1.
Machines universelles. La puissance d’expressivité des machines de Turing se révèle égale- ment au travers de la notion de machines de Turing universelles. Turing a démontré qu’il existait des machines de Turing M = (Q, Γ, δ, q 0 , F ) pouvant simuler les calculs de toutes machines de Turing. Informellement, pour que M puisse simules M ′^ il s’agit de montrer comment encoder le quintuplet M ′^ = (Q′, Γ′, δ′, q′ 0 , F ′) décrivant M ′^ sur le ruban de M. En fait c’est exactement ce que fait un ordinateur : le programmeur rentre un programme et des données, et le programme est exécuté sur les données. Mais la notion de machine de Turing universelle dit plus : elle montre qu’il n’y a pas de différence formelle entre données et programme. Les deux sont en fait des données pour une machine de Turing universelle.
2.1.2 Indécidabilité
Exite-t-il une méthode algorithmique permettant de résoudre tous les problèmes? Non! Il existe en effet des problèmes qui ne sont pas décidables, c’est-à-dire pour lesquels il n’existe pas
n’existait pas de différence formelle entre programmes et données. Nous pouvons donc construire le programme diag prenant en entrée une chaîne de caractères x, comme suit :
Algorithme diag(x) : début si halt(x, x) = 1 alors tant que vrai faire b ← 0 /* boucle infinie */ sinon stop fin
Le programme ci-dessus n’est rien d’autre qu’une chaîne de caractères, diag. On peut donc étudier la valeur de halt(diag, diag) : — Si halt(diag, diag) = 1 alors, par définition de halt, le programme diag s’arrête sur le chaîne de caractères diag. Cela est en contradiction avec la définition de diag qui boucle indéfiniment sur une chaîne de caractère x telle que halt(x, x) = 1. — Si halt(diag, diag) = 0 alors, par définition de halt, le programme diag ne s’arrête pas sur le chaîne de caractères diag. Cela est en contradiction avec la définition de diag qui s’arrête immédiatement sur une chaîne de caractère x telle que halt(x, x) = 0. Les deux cas conduisant à une contradiction, il ne peut donc pas exister de programme halt.
En d’autres termes, le théorème de l’arrêt indique qu’il n’existe pas de méthode générique permettant de prouver qu’un programme est correcte. Ainsi, vérifier si le programme de contrôle d’une centrale nucléaire est correct est une tâche extrêmement ardue, voire potentiellement impossible si ce programme n’offre pas des caractéristiques spécifiques. Un moyen de prouver des programmes consiste à restreindre l’expressivité du langage de programmation (cf. certaines versions du λ-calcul). Ainsi, la correction des programmes contrôlant les métros automatiques repose soit sur des procédures de vérifications formelles de programmes peu expressifs, soit sur des techniques spécifiques du programme à vérifier.
Notons que le problème de l’arrêt de la machine de Turing, ou celui de l’isomorphisme de groupes, peuvent sembler abstraits, et on peut croire que l’indécidabilité de ces problèmes provient de ce caractère abstrait. Il n’en est rien, et des problèmes très simples peuvent se révéler indécidables! Par exemple, le problème suivant est indécidable :
Le problème produit matrice nul : Entrée : un ensemble S de six matrices 3 × 3 à coeffi- cients rationnels ; Question : peut-on obtenir la matrice nulle par produit de matrices de S entre elles (avec répétition)?
Notons que le problème produit matrice nul est décidable pour deux matrices 2 × 2 (avec un algorithme déjà non trivial). La décidabilité du problème pour trois matrices 2 × 2 n’est pas connu, ni pour deux matrices 3 × 3. En revanche, le problème est indécidable pour deux matrices 15 × 15. Notons que dans tous ces cas, la longueur de la séquence de produits permettant d’obtenir la matrice nulle (si une telle séquence existe) peut être arbitrairement longue.
Si la machine de Turing donne un cadre formel à la théorie de la complexité, ce n’est gé- néralement pas avec ce modèle que l’on analyse les algorithmes ou que l’on juge au quotidien de la difficulté d’un problème. On utilise plutôt un autre modèle, d eplus haut niveau et plus
malléable : le modèle RAM, pour random-acces machine. Ce modèle est suffisant pour juger de la difficulté d’un problème, à une fonction polynomiale près de la taille des données du problème.
2.2.1 Les modèles de machines RAM
Le modèle RAM inclut : — une mémoire infinie dont chaque cellule peut contenir un entier, — un nombre fini de registres pouvant contenir un entier, et — une unité de calcul exécutant une suite finie d’instructions élémentaires. L’instruction effectuée à chaque étape de calcul dépend de l’état des registres (c’est-à-dire de leur contenu), ce qui inclu le compteur de programme. Une telle instruction peut consister en charger le contenu d’une cellule mémoire dans un registre, ou écrire le contenu d’un registre dans une cellule mémoire. Le modèle RAM permet également l’utilisation des instructions arith- métiques élémentaires +, −, ∗, /, et de comparaisons <, =, >, entre contenus de registres. Il permet également d’effectuer toutes les instructions usuelles comme les branchements condition- nels (si/alors/sinon), les boucles (tant que/faire, pour/faire, faire/jusqu’à), ainsi que l’adressage indirect (c’est-à-dire l’accès à une cellule dont la position est décrite par le contenu d’un registre).
On distingue alors deux types de machines RAM :
Le modèle de la machine RAM uniforme suppose que chacune des opérations arithmé- tiques listées ci-dessus prend un temps 1. Comme tel, ce modèle est considéré trop puissant, principalement parce qu’il est capable d’effectuer des opérations arithmétiques sur des entiers de taille arbitrairement grande en temps constant. De fait, on ne connaît pas de simulation en temps polynomial de la machine RAM uniforme par une machine de Turing. (En revanche, si l’on se restreint aux opérations arithmétiques + et −, alors il est possible de montrer que la machine RAM uniforme est équivalente à la machine de Turing par simulations réciproques en temps polynomial).
Le modèle de la machine RAM logarithmique suppose que chaque opération arithmétique +, −, ∗, / et de comparaison <, =, > prend un temps proportionnel au logarithme de la taille des entiers impliqués dans l’opération. Ce modèle est équivalent à la machine de Turing par simulations réciproques en temps polynomial. C’est-à-dire tout programme RAM s’exécutant en temps t(n) peut être simulé par une machine de Turing s’exécutant en temps O(t(n)c) pour c > 0 constant.
Exemple. Considérons les deux algorithmes suivants :
Algorithme puissance(n) : début y ← 1 pour i = 1 à n faire y ← 2 y fin
Ce premier algorithme calcule y = 2n. Le second algorithme ci-dessous calcule y = 2^2 n . Algorithme puissance2(n) : début y ← 2 pour i = 1 à n faire y ← y^2 fin
Chacun de ces deux algorithmes effectue O(n) opérations, dont n multiplications. Ils ont donc
nous contenterons de manipuler principalement des entiers relatifs codés en binaire, et parfois des rationnels approximés par une représentation binaire tronquée à = 2−k^ près. Par exemple
1 3
i=
2 −^2 i
sera approximé en x = 0.010101 =
∑k/ 2 i=1 2 − 2 i (^) satisfaisant | 1 3 −^ x| ≤^ ^ =^
1 2 k^.
Un des objectif de la complexité algorithmique est de classer chaque problème selon sa diffi- culté, c’est-à-dire selon la complexité du meilleur algorithme permettant de résoudre ce problème. Une des classes les plus importantes est la classe p des problèmes pouvant se résoudre en temps polynomial en la taille des données. Cette classe est considérée comme celle des problème « fa- cile », au sens où si la donnée est de taille N alors le temps pour résoudre le problème sur cette donnée sera au plus O(N c) avec c ≥ 0. Bien sûr, si c = 100 alors il semble absurde de dire que le problème est facile. Toutefois, pour la très grande majorité des problèmes « naturels » de p, il existe un algorithme les résolvant s’exécutant en temps O(N c) avec c petit.
2.3.1 Les problèmes de décision
En fait, la complexité fait référence à des problèmes de décision relatifs à décider si un mot appartient à un langage. Soit Σ un alphabet fini, par exemple Σ = { 0 , 1 }, et soit Σ∗^ l’ensemble de tous les mots finis sur cet alphabet (y compris le mot vide ). Un langage est un sous-ensemble L de Σ∗. Un problème de décision s’exprime alors sous la forme suivante. Soit L un langage de Σ∗^ :
Le problème Décider L : Entrée : un mot x de Σ∗^ ; Question : x ∈ L?
Bien que cette présentation des problèmes puisse sembler très abstraite, il n’en est rien. Pre- nons par exemple le cas du problème produit matrice nul introduit précédemment. Chaque matrice 3 × 3 nécessite 9 entiers. Une instance du problème consiste donc en 54 rationnels (ou entiers, une fois normalisés). Le langage L considéré dans le problème est celui des chaines de 54 entiers, correspondant donc à un ensemble de six matrices 3 × 3 , telles qu’il existe une façon de combiner ces matrices par produit de façon à obtenir la matrice nulle.
A titre d’autre exemple, considérons le problème ustcon (pour undirected s-t-connectivity) qui, étant donné un graphe G = (V, E) et deux sommets s, t ∈ V , doit décider s’il existe une chemin dans G entre s et t. Le langage considéré est celui des graphes G et des paires de sommets (s, t) pour lesquels il existe un chemin entre s et t. Si l’on code tout graphe G = (V, E) de n sommets en numérotant ses sommets de 1 à n, et en utilisant une matrice d’adjacence M , c’est- à-dire Mi,j = 1 ⇐⇒ {i, j} ∈ E, alors les données de ustcon sont une matrice booléenne n × n, et deux entiers s, t ∈ { 1 ,... , n}. Le langage L correspondant à ustcon peut être défini comme suit : (G, s, t) ∈ L si et seulement si il existe une suite d’indices j 0 , j 1 ,... , jk dans { 1 ,... , n} tel que s = j 0 , t = jk, et pour tout i = 0,... , k − 1 on a Mji,ji+1 = 1. Notons que, une fois
compacte exacte de telles nombres sujets à des opérations arithmétiques complexes est l’objet d’une domaine de recherche propre : le calcul formel.
« codées en machine », les données G, s et t forment une chaîne de bits, c’est-à-dire un mot de Σ∗^ = { 0 , 1 }∗.
2.3.2 La classe p
Pour un mot x ∈ Σ∗, on note |x| la taille de x, c’est-à-dire le nombre de symboles (ou lettres) de x (souvent, simplement le nombre de bits). On dit qu’un algorithme A résolvant un problème de décision est polynomial s’il existe c ≥ 0 tel que pour tout x ∈ Σ∗, A s’exécute en temps O(|x|c). On note A(x) la décision retournée par A sur la donnée x : A(x) ∈ {oui, non}. Lorsque A(x) = oui, on dit que A accepte x, et sinon on dit que A rejette x.
Exemple. Considérons le langage L formé par l’ensemble des matrices inversibles. Etant donné une matrice M , on souhaite savoir si M ∈ L, c’est-à-dire si M est inversible. Une matrice est inversible si et seulement si son déterminant est non nul. Pour décider L, un algorithme consiste donc à calculer le déterminant de M par la formule de Leibniz, et à accepter M si et seulement si ce déterminant est non nul. Cet algorithme n’est toutefois pas polynomial car calculer la formule de Leibniz pour une matrice n × n nécessite de l’ordre de n! opérations arithmétiques. Un autre algorithme consiste à utiliser l’algorithme de l’élimination de Gauss-Jordan pour inverser M (qui, en particulier signale si M n’est pas inversible). Cet algorithme s’exécute en au plus O(n^3 ) opérations élémentaires. Il est dont polynomial en la taille de M (décrite sous la forme de n^2 entiers).
Definition 2 La classe p consiste en tous les langages L pour lesquels il existe un algorithme A polynomial en la taille de x tel que pour tout x ∈ Σ∗^ : A accepte x si et seulement si x ∈ L, c’est-à-dire : x ∈ L ⇐⇒ A accepte x
Informellement, la classe p est donc la classe de tous les problèmes de décision qui peuvent se résoudre en temps polynomial. Ainsi, par exemple, le langage L = {matrices inversibles} est dans p (l’algorithme de décision est celui de l’élimination de Gauss-Jordan). Par exemple, un graphe coloré est un graphe G = (V, E) muni d’une fonction c : V → N affectant à chaque sommet u une couleur c(u). Un graphe est proprement coloré si, pour chaque sommet, la couleur de ce sommet est différente de la couleur de ses voisins. Soit L = {graphes proprement colorés}. On a L ∈ p, comme le démontre l’algorithme ci-dessous qui suppose que G est décrit par sa matrice d’adjacence M :
Algorithme decide-coloration-propre(G, c) : début col-propre ← vrai pour i = 1 à n faire pour j = 1 à n faire si M [i, j] = 1 et c(i) = c(j) alors col-propre ← faux retourner col-propre fin La taille d’une instance est Ω(n^2 ) puisque la matrice d’adjacence M de G est de taille n × n, et l’algorithme effectue O(n^2 ) opérations élémentaires. Cet algorithme est donc polynomial (il est en fait même linéaire en la taille des données). On peut écrire un algorithme en temps O(m) si G est décrit par listes d’adjacence L :
satisfaisant les propriétés P 1 ,... , Pm où chaque propriété Pi est de la forme alternative, q 1 ou q 2 ou.. .ou qk. Par exemple, retourner tous les auteurs de romans espagnols, italiens, ou français ayant vécu au XVII ou au XVIIIème siècle. Les Ci =
∨ki j=1 `i,j^ sont les^ clauses^ de la formule^ F^. Ci est de longueur ki.
Notons que, pour toute affectation de x 1 , x 2 , et x 3 à vrai ou faux, la formule F 1 est toujours fausse. En revanche, la formule F 2 est vraie pour x 1 = vrai, x 3 = faux, x 4 = vrai, et x 2 quelconque. On peut stocker une formule F en FNC de plusieurs façons équivalentes à une réduction polynomiale près (de la même façon que les codages d’un graphe en matrice d’adjacence et en liste d’adjacence sont équivalents). Par exemple, une formule de n variables x 1 ,... , xn sur m clauses C 1 ,... , Cm peut être codée comme une matrice F de taille m × n, où Fi,j ∈ {− 1 , 0 , 1 } telle que :
Fi,j =
0 si le littéral xj n’apparaît pas dans la clause Ci 1 si le littéral xj apparaît pas dans la clause Ci sous forme positive (xi) − 1 si le littéral xj apparaît dans la clause Ci sous forme négative ( x¯i)
Le problème sat est alors le suivant :
Le problème sat : Entrée : une formule booléenne F sous FNC ; Question : existe-t-il une affectation des variables booléennes de F telle que F soit vraie?
Pour tout entier k ≥ 0 , le problème k-sat est le problème sat restreint aux FNC dont les clauses sont de longueur au plus k.
Exercice 2 Montrer que le problème 2 - sat est dans p.
Alors qu’il est trivial de donner un algorithme exponentiel résolvant sat par tests successifs des 2 n^ valeurs possibles des n variables booléennes de la formule, on ne connaît pas d’algorithme polynomial pour ce problème. Notez que tester 2 n^ valeurs est irréaliste dès que n dépasse quelques dizaines, même sur un ordinateur ultra-puissant. Ce fait est illustré dans le figure 6.
En fait, il est fortement suspecté qu’il n’existe pas d’algorithme polynomial pour sat, mais cela reste toutefois au titre de conjecture, malgré près de cinquante années d’efforts de la com- munauté. Démontrer la non existence d’un algorithme polynomial pour un problème (ou un langage) arbitraire est une tâche extrêmement complexe. Il convient toutefois de remarquer un fait intriguant à propos de sat. Trouver rapidement (c’est-à-dire en temps polynomial) les va- leurs des variables booléennes susceptibles de rendre vraie la formule semble très difficile. En revanche, si la formule est satisfiable et que quelqu’un (disposant des capacités de l’oracle de Delphes) devine l’affectation correspondante des variables, alors vérifier que cette affectation rend effectivement vraie la formule se fait en temps polynomial (en temps au plus le nombre de clauses fois le nombre maximum de littéraux par clauses), par exemple au moyen de l’algorithme suivant :
Algorithme verification(F, x) : début a ← vrai pour i = 1 à m faire b ← faux
http://www.jucs.org/jucs_2_2/on_the_scalability_of/Mac_Donaill_D_A.html Page 2 sur 6
Collection of other papers
1.1 Classification of Problem Complexity Time complexity functions describe how the cost of solving a problem grows on increasing the size (or input length), n, of the problem. Computer scientists recognize two distinct classes [ Garey and Johnson 1979 ]. Algorithms for which the time complexity function is O(p(n)), where p(n) is a polynomial in n, are termed polynomial time algorithms, whereas algorithms with no polynomial bound on their complexity are called exponential time algorithms. There is a remarkable difference in growth rates between polynomial and exponential algorithms [Fig. 1].
Figure 1: Time complexity functions for some polynomial (n, ) and exponential ( ) functions as a function of problem size, n. Page 88 Problems with polynomial algorithms are considered "good", whereas problems which are so difficult that no polynomial time algorithm can solve them are termed "intractable". The theory of NP-completeness is concerned with decision problems. Informally, a decision problem is said to belong to the class P if there exists a Deterministic Turing Machine (DTM) program which solves the problem in polynomial time. Non-deterministic computation differs from deterministic computation in that a solution is exhaustively guessed and then checked. If a correct solution to a decision problem can be checked in polynomial time, then that problem is said to belong to the class NP (Non-deterministic Polynomial time). Since problems which can be solved deterministically in polynomial time can also be guessed non- deterministically and checked in polynomial time, we can write P NP [Fig. 2]. It is not known whether this inclusion is proper, that is whether NP\P is occupied. A practical difficulty with problems in NP is that their time-complexity with a deterministic algorithm is exponential. Thus problems in NP are intractable with deterministic machines. Certain problems in NP have the property that all other problems in NP may be polynomially reduced to them, and are termed NP-complete. If a polynomial time algorithm can be found for any member of this equivalence class then one can be found for all problems in NP. In other words, if for any (problem) NP-complete, then P if and only if P = NP. Problems NP-complete may be regarded as the hardest problems in NP. The relationship between P, NP and NP-complete is illustrated below
Figure 6 – Différence entre le temps de calcul polynomial et exponentiel. On suppose qu’une opération élémentaire s’effectue en 10 −^6 secondes. Un algorithme linéaire (i.e., s’exécutant en temps n) prendra 10 −^4 secondes pour traiter un problème de taille 100, alors qu’un algorithme quadratique prendra un temps 10 −^2 secondes. Un algorithme exponentiel, disons en temps 2 n, prendra... 400.000 milliard d’années, soit environ 20.000 fois l’âge estimé de l’univers.
pour j = 1 à n faire si
(F [i, j] = 1 et x[j] = vrai) ou (F [i, j] = − 1 et x[j] = faux)
alors b ← vrai a ← a ∧ b retourner a fin Cet algorithme prend en entrée une instance codée sur O(nm) bits, et effectue O(mn) opé- rations élémentaire. Il est donc polynomial. Dit autrement, si la réponse à sat est oui, c’est-à-dire si la formule en entrée est satisfiable, alors il existe un certificat qui vous permet de vous convaincre que la formule est effectivement satisfiable. De plus, l’algorithme de vérification est fiable, au sens que si quelqu’un essaie de vous tromper en prétendant qu’une formule non satisfiable est satisfiable, il ne sera pas en mesure de vous fournir un certificat accepté par l’algorithme. La classe np est la classe des problèmes pour lesquels, comme pour sat, il existe un certificat de taille polynomial permettant de vérifier la solution en temps polynomial et de façon fiable (on ne peut pas tromper l’algorithme de vérification avec un faux certificat). Plus formellement :
Definition 3 La classe np consiste en tous les langages L pour lesquels il existe un algorithme polynomial A tel que pour tout x ∈ Σ∗^ : — si x ∈ L alors il existe y ∈ Σ∗^ de taille polynomiale en la taille de x tel que A(x, y) accepte ; — si x /∈ L alors pour tout y ∈ Σ∗, A(x, y) rejette. Dis autrement, il existe c ≥ 0 tel que, pour tout x ∈ Σ∗^ :
x ∈ L ⇐⇒ ∃ y ∈ Σ∗^ : |y| = O(|x|c) et A(x, y) accepte.
Le mot y ∈ Σ∗^ est appelé certificat.
On impose que la taille |y| du certificat soit polynomiale en la taille |x| de l’entrée x, car il est