web-dev-qa-db-fra.com

Est-ce que ma fonction est O (n!) Ou est O((n-1)!) plus précise?

J'ai écrit un algorithme de recherche en force brute pour le problème du voyageur de commerce et je l'ai testé pour voir le temps qu'il faut pour un grand nombre de «villes». Le graphique ci-dessous montre que le temps est approximativement proportionnel à (n-1)!, où n est le nombre de «villes». Ce n'est pas directement proportionnel à n! (après tout, (n-1)! = n! / n).

Ma question est la suivante: est-il toujours correct de dire que l'algorithme fonctionne dans O(n!) ou est-il préférable que je dis O((n-1)!)? Je n'ai jamais vu ce dernier auparavant, mais cela semble plus précis. Il semble que j'ai mal compris quelque chose ici.

 

[t = temps pris, n = nombre de villes]

19
monopole

Par définition, O(f(n)) est l'ensemble de toutes les fonctions asymptotiquement dominées par f (n), c'est-à-dire l'ensemble de toutes les fonctions g(n) pour lesquelles il y a des constantes C et n_0 telles que

g(n) < C * f(n)   for all n > n_0

De cette définition, il en résulte que O (n!) Est en fait un super ensemble de O ((n-1)!), Puisque la fonction f(n) = n! est un membre du premier ensemble, mais pas du deuxième ensemble. Les deux ensembles ne sont pas vraiment les mêmes.

Cependant, il est correct de dire que votre problème est O (n!), Car il ne s'agit que d'une limite supérieure. Il ne serait pas correct de dire que votre problème est ϴ (n!), Car cela dénote le comportement asymptotique exact jusqu’à facteurs constants.

Il n'y a pas de grande différence dans la pratique et, comme indiqué dans une autre réponse, vous pouvez redéfinir n pour désigner le nombre de villes moins une.

49
Sven Marnach

O(n!) est assez bon. n ou n-1 ne fait aucune différence pour les grands n.

Voir https://www.wikiwand.com/en/Time_complexity#/Table_of_common_time_complexities Pour des exemples. 

5
Bartosz Bilicki

La réponse de Sven Marnach est très bonne, je voudrais juste élaborer un peu sur cette partie: 

ou est-ce mieux pour moi de dire O ((n-1)!)?

Comme d’autres l’ont dit, O(n) est généralement suffisant. Si vous voulez en savoir plus sur le problème, vous pouvez essayer de trouver et de prouver:

  • Une borne inférieure (généralement notée Ω(n)
  • Une limite supérieure serrée

Une borne inférieure indique fondamentalement que, sous certaines asymptions, aucun algorithme ne peut résoudre le problème de manière asymptotiquement plus rapide. Une limite supérieure étroite est une limite supérieure qui correspond à une limite inférieure, c’est-à-dire que vous devez prouver une limite inférieure de Ω(f(n)) et une limite supérieure de O(f(n)). Si vous pouvez prouver une limite inférieure et une limite supérieure strictes, cela signifie que votre algorithme est un algorithme asymptotiquement optimal pour le problème. 

Pour vous donner un exemple concret, vous connaissez sûrement les algorithmes de tri tels que le tri par fusion ou le tri rapide et leur limite supérieure de O(n log n)). Donald Knuth a montré (il y a plusieurs décennies) que les algorithmes de tri basé sur la comparaison pour les entiers nécessitent au moins __ comparaisonsn log n, c'est-à-dire, opérations Ω(n log n). Étant donné que nous avons une limite supérieure correspondante, les deux types de fusion et de tri rapide sont dits asymptotiquement optimaux (bien que leurs performances diffèrent beaucoup dans la pratique).

1
mort

Vous pouvez simplement prouver que:

O ((n-1)!) Signifie qu'il y a une constante c telle que:

étapes de l'algorithme (ou complexité temporelle) <c (n-1)! <c n!/n <c n! pour tout n> 1.

Donc, puisque votre fonction pour la complexité de l’algorithme tient: Étapes de l’algorithme (ou complexité du temps)

votre algorithme est aussi O (n!).

Nous avons donc prouvé que si la complexité temporelle de votre algorithme est O ((n-1)!), Il s'agit également de O (n!).

1
coder