Qu'est-ce que le temps pseudopolynomial ? En quoi diffère-t-il du temps polynomial? Certains algorithmes qui fonctionnent en temps pseudopolynomial ont des temps d'exécution tels que O (nW) (pour le problème de sac à dos 0/1 ) ou O (√n) (pour la division d'essai ); pourquoi cela ne compte-t-il pas comme un temps polynomial?
algorithm
big-o
time-complexity
templatetypedef
la source
la source
Réponses:
Pour comprendre la différence entre le temps polynomial et le temps pseudopolynomial, nous devons commencer par formaliser ce que signifie «temps polynomial».
L'intuition commune pour le temps polynomial est «le temps O (n k ) pour un certain k». Par exemple, le tri par sélection s'exécute au temps O (n 2 ), qui est le temps polynomial, tandis que la résolution par force brute TSP prend le temps O (n · n!), Qui n'est pas un temps polynomial.
Ces runtimes font tous référence à une variable n qui suit la taille de l'entrée. Par exemple, dans le tri par sélection, n fait référence au nombre d'éléments dans le tableau, tandis que dans TSP n fait référence au nombre de nœuds dans le graphique. Afin de normaliser la définition de ce que signifie réellement «n» dans ce contexte, la définition formelle de la complexité temporelle définit la «taille» d'un problème comme suit:
Par exemple, si l'entrée d'un algorithme de tri est un tableau d'entiers 32 bits, alors la taille de l'entrée serait de 32n, où n est le nombre d'entrées dans le tableau. Dans un graphe avec n nœuds et m arêtes, l'entrée pourrait être spécifiée comme une liste de tous les nœuds suivie d'une liste de tous les arêtes, ce qui nécessiterait Ω (n + m) bits.
Compte tenu de cette définition, la définition formelle du temps polynomial est la suivante:
Lorsque vous travaillez avec des algorithmes qui traitent des graphiques, des listes, des arbres, etc., cette définition est plus ou moins en accord avec la définition conventionnelle. Par exemple, supposons que vous ayez un algorithme de tri qui trie des tableaux d'entiers 32 bits. Si vous utilisez quelque chose comme le tri par sélection pour ce faire, le runtime, en fonction du nombre d'éléments d'entrée dans le tableau, sera O (n 2 ). Mais comment n, le nombre d'éléments dans le tableau d'entrée, correspond-il au nombre de bits d'entrée? Comme mentionné précédemment, le nombre de bits d'entrée sera x = 32n. Par conséquent, si nous exprimons le temps d'exécution de l'algorithme en termes de x plutôt que n, nous obtenons que le temps d'exécution est O (x 2 ), et donc l'algorithme s'exécute en temps polynomial.
De même, supposons que vous effectuez une recherche en profondeur d'abord sur un graphe, ce qui prend le temps O (m + n), où m est le nombre d'arêtes dans le graphe et n est le nombre de nœuds. Comment cela se rapporte-t-il au nombre de bits d'entrée donné? Eh bien, si nous supposons que l'entrée est spécifiée comme une liste de contiguïté (une liste de tous les nœuds et arêtes), alors comme mentionné précédemment, le nombre de bits d'entrée sera x = Ω (m + n). Par conséquent, le runtime sera O (x), donc l'algorithme s'exécute en temps polynomial.
Les choses s'effondrent cependant lorsque nous commençons à parler d'algorithmes qui fonctionnent sur des nombres. Considérons le problème de tester si un nombre est premier ou non. Étant donné un nombre n, vous pouvez tester si n est premier en utilisant l'algorithme suivant:
Quelle est donc la complexité temporelle de ce code? Eh bien, cette boucle interne s'exécute O (n) fois et effectue à chaque fois un certain travail pour calculer n mod i (en tant que borne supérieure vraiment conservatrice, cela peut certainement être fait dans le temps O (n 3 )). Par conséquent, cet algorithme global s'exécute dans le temps O (n 4 ) et peut-être beaucoup plus rapidement.
En 2004, trois informaticiens ont publié un article intitulé PRIMES is in P donnant un algorithme de temps polynomial pour tester si un nombre est premier. Il a été considéré comme un résultat historique. Alors, quel est le problème? N'avons-nous pas déjà un algorithme de temps polynomial pour cela, à savoir celui ci-dessus?
Malheureusement, nous ne le faisons pas. Rappelez-vous, la définition formelle de la complexité temporelle parle de la complexité de l'algorithme en fonction du nombre de bits d'entrée. Notre algorithme s'exécute dans le temps O (n 4 ), mais qu'est-ce que c'est en fonction du nombre de bits d'entrée? Eh bien, l'écriture du nombre n prend O (log n) bits. Par conséquent, si nous laissons x le nombre de bits nécessaires pour écrire l'entrée n, le temps d'exécution de cet algorithme est en fait O (2 4x ), qui n'est pas un polynôme en x.
C'est le cœur de la distinction entre le temps polynomial et le temps pseudopolynomial. D'une part, notre algorithme est O (n 4 ), qui ressemble à un polynôme, mais d'autre part, sous la définition formelle du temps polynomial, ce n'est pas un temps polynomial.
Pour comprendre pourquoi l'algorithme n'est pas un algorithme en temps polynomial, pensez à ce qui suit. Supposons que je souhaite que l'algorithme fasse beaucoup de travail. Si j'écris une entrée comme celle-ci:
il faudra alors un certain temps, par exemple
T
, pour terminer. Si j'ajoute maintenant un seul bit à la fin du nombre, comme ceci:Le runtime sera désormais (dans le pire des cas) 2T. Je peux doubler la quantité de travail de l'algorithme simplement en ajoutant un bit de plus!
Un algorithme s'exécute en temps pseudopolynomial si le temps d'exécution est un polynôme dans la valeur numérique de l'entrée , plutôt que dans le nombre de bits requis pour le représenter. Notre premier algorithme de test est un algorithme de temps pseudopolynomial, puisqu'il s'exécute dans le temps O (n 4 ), mais ce n'est pas un algorithme de temps polynomial car en fonction du nombre de bits x nécessaires pour écrire l'entrée, le runtime est O (2 4x ). La raison pour laquelle le papier "PRIMES is in P" était si significatif était que son temps d'exécution était (à peu près) O (log 12 n), qui en fonction du nombre de bits est O (x 12 ).
Alors pourquoi est-ce important? Eh bien, nous avons de nombreux algorithmes de temps pseudopolynomiaux pour factoriser les entiers. Cependant, ces algorithmes sont, techniquement, des algorithmes à temps exponentiel. Ceci est très utile pour la cryptographie: si vous souhaitez utiliser le cryptage RSA, vous devez pouvoir être sûr que nous ne pouvons pas factoriser facilement les nombres. En augmentant le nombre de bits dans les nombres à une valeur énorme (par exemple, 1024 bits), vous pouvez rendre le temps nécessaire à l'algorithme de factorisation en temps pseudopolynomial si grand qu'il serait complètement et totalement impossible de factoriser le Nombres. Si, par contre, nous pouvons trouver un algorithme de factorisation en temps polynomial , ce n'est pas forcément le cas. L'ajout de plus de bits peut faire augmenter considérablement le travail, mais la croissance ne sera qu'une croissance polynomiale, pas une croissance exponentielle.
Cela dit, dans de nombreux cas, les algorithmes de temps pseudopolynomiaux conviennent parfaitement car la taille des nombres ne sera pas trop grande. Par exemple, le tri de comptage a le temps d'exécution O (n + U), où U est le plus grand nombre du tableau. Il s'agit d'un temps pseudopolynomial (car la valeur numérique de U nécessite l'écriture de O (log U) bits, donc le temps d'exécution est exponentiel dans la taille d'entrée). Si nous contraignons artificiellement U afin que U ne soit pas trop grand (disons, si nous laissons U être 2), alors le temps d'exécution est O (n), qui est en fait le temps polynomial. Voici comment fonctionne le tri par base : en traitant les nombres un bit à la fois, le temps d'exécution de chaque tour est O (n), donc le temps d'exécution global est O (n log U). C'est en fait temps polynomial, car l'écriture de n nombres à trier utilise Ω (n) bits et la valeur de log U est directement proportionnelle au nombre de bits requis pour écrire la valeur maximale dans le tableau.
J'espère que cela t'aides!
la source
isPrime
la complexité de s est-elle estimée comme O (n ^ 4) et pas simplement O (n)? Je ne comprends pas. À moins que la complexité den mod i
soit O (n ^ 3) .... ce qui ne l'est sûrement pas.n mod i
est trop prudent. La synchronisation demod
est une fonction du nombre de bits dansn
, pas len
lui - même, donc il devrait être O ((log n) ^ 3).La complexité temporelle pseudo-polynomiale signifie polynôme dans la valeur / amplitude de l'entrée mais exponentielle dans la taille de l'entrée.
Par taille, nous entendons le nombre de bits requis pour écrire l'entrée.
À partir du pseudo-code de sac à dos, nous pouvons trouver la complexité temporelle O (nW).
Ici, W n'est pas polynomial dans la longueur de l'entrée, ce qui le rend pseudo-polynomial.
Soit s le nombre de bits requis pour représenter W
Maintenant,
running time of knapsack
= O (nW) = O (n * 2 ^ s) qui n'est pas polynomial.la source