Pourquoi le problème du sac à dos est-il pseudo-polynomial?


87

Je sais que Knapsackc'est NP-complet alors qu'il peut être résolu par DP. Ils disent que la solution DP est pseudo-polynomial, car elle est exponentielle dans la "longueur d'entrée" (c'est-à-dire le nombre de bits nécessaires pour coder l'entrée). Malheureusement, je ne l'ai pas compris. Quelqu'un peut-il m'expliquer cette pseudo-polynomialchose lentement?


Réponses:


89

Le temps d'exécution est O (NW) pour un problème de sac à dos illimité avec N articles et un sac à dos de taille W. W n'est pas polynomial dans la longueur de l'entrée, ce qui le rend pseudo- polynomial.

Considérez W = 1 000 000 000 000. Il ne faut que 40 bits pour représenter ce nombre, donc taille d'entrée = 40, mais le temps d'exécution de calcul utilise le facteur 1 000 000 000 000 qui est O (2 40 ).

Ainsi, le temps d'exécution est plus précisément dit O (N.2 bits dans W ), ce qui est exponentiel.

Regarde aussi:


1
Le lien n ° 3 faisant référence à "Complexité de la programmation dynamique pour le problème du sac à dos 0-1" est mort.
dev_nut

1
Désolé, je ne l'ai pas compris. Disons que si nous avons un algorithme de complexité temporelle O (N), alors nous avons O (2 ^ (bits dans N)), qui est exponentiel? Merci ~
Lusha Li

3
@LushaLi Cela m'a aidé: youtube.com/watch?v=9oI7fg-MIpE . Si N est un tableau où chaque élément a une entrée de taille maximale fixe (disons que chaque élément du tableau ne dépasse pas 32 bits) et que vous exécutez une fois une boucle for sur ce tableau, alors il s'agit d'un algorithme de temps polynomial dans l'entrée taille N du tableau. Cependant, si N est un entier et que vous exécutez une boucle sur N, alors N est illimité et croît de manière exponentielle dans le nombre de bits nécessaires pour le représenter. Ainsi, une simple boucle for sur N est, en fait, exponentielle. Notez que dans le cas du tableau, la taille de chaque élément du tableau était délimitée par le haut.
max_max_mir

Je n'étais pas convaincu. Il existe de nombreux algorithmes avec les mêmes propriétés qui ne sont pas «pseudo-polynomiaux». Dites, quelle est la complexité de Sieve of Eratosthenes (ou de tout autre chercheur de nombres premiers)?
Ofir A.

31

Dans la plupart de nos problèmes, nous avons affaire à de grandes listes de nombres qui s'intègrent confortablement dans les types de données standard int / float. En raison de la façon dont la plupart des processeurs sont construits pour gérer des nombres de 4 à 8 octets à la fois sans coût supplémentaire (par rapport aux nombres qui ne rentrent pas dans, disons, 1 octet), nous rencontrons rarement un changement dans le temps de fonctionnement à dans les gammes que nous rencontrons dans les problèmes réels - le facteur dominant reste donc simplement la quantité de points de données, les facteurs n ou m auxquels nous sommes habitués.

(Vous pouvez imaginer que la notation Big-O cache un facteur constant qui divise 32 ou 64 bits par donnée, ne laissant que le nombre de points de données chaque fois que chacun de nos nombres tient dans autant de bits ou moins )

Mais essayez de retravailler avec d'autres algorithmes pour agir sur des ensembles de données impliquant de gros entiers - des nombres qui nécessitent plus de 8 octets pour être représentés - et voyez ce que cela fait à l'exécution. L'ampleur des nombres impliqués fait toujours une différence, même dans les autres algorithmes comme le tri binaire, une fois que vous étendez au-delà de la mémoire tampon de sécurité, les processeurs conventionnels nous donnent "gratuitement" en traitant des lots de 4 à 8 octets.

L'astuce avec l'algorithme Knapsack dont nous avons discuté est qu'il est inhabituellement sensible (par rapport à d'autres algorithmes) à la grandeur d'un paramètre particulier, W.Ajoutez un bit à W et vous doublez le temps d'exécution de l'algorithme. Nous n'avons pas vu ce genre de réponse dramatique aux changements de valeur d'autres algorithmes avant celui-ci, c'est pourquoi il peut sembler que nous traitons Knapsack différemment - mais c'est une véritable analyse de la façon dont il répond de manière non polynomiale. aux changements de taille d'entrée.


8

Le temps d'exécution de l'algorithme Knapsack est lié non seulement à la taille de l'entrée (n - le nombre d'articles) mais également à l'amplitude de l'entrée (W - la capacité du sac à dos) O (nW) qui est exponentielle dans sa façon représenté en ordinateur en binaire (2 ^ n). La complexité de calcul (c'est-à-dire comment le traitement est effectué à l'intérieur d'un ordinateur via des bits) ne concerne que la taille des entrées, pas leurs grandeurs / valeurs .

Ne tenez pas compte de la liste des valeurs / poids pendant un moment. Disons que nous avons une instance avec une capacité de sac à dos 2. W prendrait deux bits dans les données d'entrée. Nous allons maintenant augmenter la capacité du sac à dos à 4, en conservant le reste de l'entrée. Notre contribution n'a augmenté que d'un peu, mais la complexité du calcul a été multipliée par deux. Si nous augmentons la capacité à 1024, nous n'aurions que 10 bits d'entrée pour W au lieu de 2, mais la complexité a augmenté d'un facteur 512. La complexité temporelle croît exponentiellement dans la taille de W en représentation binaire (ou décimale) .

Un autre exemple simple qui m'a aidé à comprendre le concept pseudo-polynomial est l'algorithme de test de primalité naïve. Pour un nombre n donné, nous vérifions s'il est divisé également par chaque nombre entier dans la plage 2..√n, donc l'algorithme prend √ (n − 1) pas. Mais ici, n est la grandeur de l'entrée, pas sa taille.

                     Now The regular O(n) case

En revanche, la recherche d'un tableau pour un élément donné s'exécute en temps polynomial: O (n). Cela prend au plus n étapes et ici n est la taille de l'entrée (la longueur du tableau).

[ vois ici ]

Calcul des bits requis pour stocker un nombre décimal


3
Donc, pour votre dernier exemple de recherche, pourquoi ne pas considérer n comme binaire aussi? si n = 1024, cela ne prend que 10 bits, alors ne devrait-il pas être pseudo-polynomial?
user1024

7

La façon dont je comprends cela est que la capacité aurait été O (W) si l'entrée de capacité était un tableau de [1,2, ..., W] , qui a une taille de W. Mais l'entrée de capacité n'est pas un tableau de nombres, c'est plutôt un seul entier. La complexité temporelle concerne la relation avec la taille de l'entrée. La taille d'un entier n'est PAS la valeur de l'entier, mais le nombre de bits le représentant. Nous convertissons plus tard cet entier W en un tableau [1,2, ..., W] dans l'algorithme, amenant les gens à penser à tort que W est la taille, mais ce tableau n'est pas l'entrée, l'entier lui-même l'est.

Considérez l'entrée comme «un tableau de choses» et la taille comme «combien de choses dans le tableau». L'entrée d'élément est en fait un tableau de n éléments dans le tableau, donc size = n. L'entrée de capacité n'est PAS un tableau de nombres W , mais un seul entier , représenté par un tableau de bits log (W). Augmentez sa taille de 1 (en ajoutant 1 bit significatif), W double donc le temps d'exécution double, d'où la complexité exponentielle du temps.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.