Je suis bloqué par l'analyse de la complexité temporelle de l'algorithme suivant:
def fun (r, k, d, p):
if d > p:
return r
if d = 0 and p = 0:
r <- r + k
return r
if d > 0:
fun (r, k + 1, d - 1, p)
if p > 0:
fun (r, k - 1, d, p - 1)
L'appel racine sera fun (0, 0, n, n)
, et n
est de la taille du problème.
Je suppose que: La relation de récurrence est , ce qui équivaut à , et donc .
Mon analyse est-elle correcte (je sais qu'elle n'est pas très complète et exacte)? S'il présente un défaut grave, veuillez le signaler ou me montrer une preuve correcte et complète de la complexité temporelle de cet algorithme.
d>0
etp>0
. Vous ne montrez pas ce que la fonction retourne si nous atteignons les 3e et 4e instructions if. Vouliez-vous avoir unereturn
déclaration après chaque invocation récursive defun
? (vouliez-vous l'fun (r, k + 1, d - 1, p)
êtrereturn fun (r, k + 1, d - 1, p)
?) Ou vouliez-vous avoir unereturn
déclaration à la toute fin du corps de la fonction? Veuillez modifier votre pseudocode pour clarifier et assurez-vous de montrer ce que cela renvoie dans tous les cas possibles.d<=p
etd>0
etp>0
tous tiennent. Que doit-il arriver? L'algorithme effectue-t-il 2 invocations récursives à la fonction? Ou invoque-t-elle récursivementfun(r, k + 1, d - 1, p)
puis revient-elle immédiatement, sans invoquer récursivementfun(r, k - 1, d, p - 1)
? Si je prends votre pseudocode littéralement, il semble qu'il effectue 2 invocations récursives puis retourne avec une valeur de retour non définie - mais cela semble étrange et me fait me demander s'il y a une faute de frappe / bogue dans le pseudocode.Réponses:
Les deux seuls arguments pertinents pour l'analyse asymptotique sont et . Ces arguments satisfont (virtuellement) et (nous devons mélanger légèrement la logique dans la fonction pour obtenir ceci). À chaque point de l'exécution, vous prenez la paire actuelle puis appelez récursivement la fonction avec les paires , en évitant les paires qui invalident les contraintes énoncées ci-dessus .ré p ré, p ≥ 0 ré≤ p ( d, p ) ( d- 1 , p ) , ( d, p - 1 )
Nous pouvons représenter l'arbre d'appel résultant comme un chemin commençant à . Chaque fois que vous diminuez , ajoutez un pas /. Chaque fois que vous diminuez , ajoutez un \ step. La condition garantit que vous ne descendez jamais en dessous de l'axe X. De plus, vous avez un "budget" de pour chaque étape. Le nombre total de feuilles dans cet arbre d'appel est exactement le nombre catalan , et cela nous donne un borne inférieure du temps d'exécution de la fonction.( 0 , 0 ) p ré ré≤ p n (2 nn) /(n+1)=Θ(4n/n3 / 2)
Pour obtenir une limite supérieure, notez que sur le chemin de chaque feuille, nous traversons nœuds, ce qui donne une limite supérieure plus grande que la limite inférieure, c'est-à-dire .2 n 2 n Θ (4n/n--√)
Nous avons une borne inférieure de et une borne supérieure sur . Quelles sont les asymptotiques exactes? Ils croissent comme le nombre total de chemins ne traversant pas l'axe X qui ont au plus pas dans chaque direction. En utilisant le théorème de vote de Bertrand, nous pouvons obtenir une expression exacte pour ceci: Il reste donc à estimer cette somme asymptotiquement:Ω (4n/n3 / 2) O (4n/n--√) n
la source
Cas par cas:
fun
revient sur d-1 jusqu'à d ≯ 0; puisque p> 0, c'est Linéaire en d + (cas 4) .fun
revient sur p-1 jusqu'à p ≯ 0; c'est linéaire en p + (un des cas 1, 2 ou 5)En commençant par d = p = n> 0 frappe le cas 3, qui est suivi par le cas 4. Si n est un nombre entier, le cas final est 2, sinon le cas final est 5. Le temps total pour ces cas est d + p +1 ou 2n + 1.
la source
if
pour "faire un de ceux-ci" tandis que @Yuval les a pris pour "considérer chacun d'eux dans l'ordre". Ce dernier est, bien sûr, ce queif
s (sanselse
) signifie dans le code réel; Je suis habitué à l'ancien dans presque tout autre contexte que le code réel (y compris dans le pseudocode, bien que l'utilisation dans le pseudocode soit incohérente).return
déclarations dans la seconde moitié du code rend cela assez déroutant.