Inscription / Connexion Nouveau Sujet
Niveau exercices
Partager :

Dérangements et algo

Posté par
flight
25-11-19 à 21:30

Bonsoir

On sait que le nombre de dérangements de n éléments peut être extrait de la factorielle de n  , en effet   n ! = C(n,k).Dn-k ,k compris entre 0 et n
Pouvez vous écrire un algo dans le langage de votre choix  permettant de calculer le  nombre de dérangements de n objets . ( on choisit un entier quelconque n>2  et le prog retourne le nombre de derangements) on pourra partir du fait que Do=1  et 1=0

Posté par
flight
re : Dérangements et algo 25-11-19 à 21:31

mal ecrit Do=1  et D1=0

Posté par
verdurin
re : Dérangements et algo 26-11-19 à 14:57

Salut,
je propose, en python

 Cliquez pour afficher

ps : j'ai optimisé le temps d'écriture de la fonction plus que le temps d'exécution d'icelle.

Posté par
Ulmiere
re : Dérangements et algo 26-11-19 à 15:54

Une solution utilisant une autre formule que celle de verdurin
Une autre utilisant une simple factorielle et une division, mais avec une précision de "seulement" 10^9999, ce qui est largement assez en pratique

 Cliquez pour afficher

Posté par
alb12
re : Dérangements et algo 26-11-19 à 16:46

 Cliquez pour afficher

Posté par
LittleFox
re : Dérangements et algo 27-11-19 à 11:46


Une autre version python basée sur la même formule que Ulmiere et alb12:

D(n) = \sum_{k=0}^n{(-1)^{k}\frac{n!}{k!}}

 Cliquez pour afficher

Posté par
Ulmiere
re : Dérangements et algo 27-11-19 à 13:09

LittleFox

 Cliquez pour afficher

Posté par
LittleFox
re : Dérangements et algo 27-11-19 à 14:13

@Ulmiere
Oui, on peut.
Mais reversed(range(n+1)) retourne bien un itérateur. Essaye de faire next(reversed(range(10**200)) il n'y aura pas de soucis.
Essaye list(range(10**200)), aucune chance que ça passe.
Et ça parce que range implémente la méthode __reversed__(self).


D'un autre côté le coût le plus élevé du programme est le fact *= k (qui devient x*-y dans ta version).
Je trouve mon programme plus clair et plus proche de l'équation de départ le tout sans perte significative d'efficacité.

J'aurais pu même faire ceci :

def derangement(n):
    """ Returns the number of derangement of n elements """
    factorial = 1
    partial_sum = 0
    for k in reversed(range(n+1)):
        partial_sum += (-1)**k * factorial
        factorial *= k
    return partial_sum

Posté par
verdurin
re : Dérangements et algo 29-11-19 à 14:17

J'ai mesuré la durée d'exécution pour le calcul de D_{1\,000} des deux programmes de LittleFox et celle d'un programme utilisant D_{n+1}=n(D_n+D_{n-1}) sans récursivité.

def derangeD(n):
    " calcule directement le nombre de dérangements pour un ensemble de taille n"
    if n==0 : return 1
    elif n==1 : return 0
    elif n==2 : return 1
    a,b = 0,1
    for k in range(2,n):
        c=k*(a+b)
        a=b
        b=c
    return c

Comme on pouvait s'y attendre le calcul direct de (-1)^k est assez pénalisant.

Sur ma machine :
la première version met environ 0,89ms, la seconde environ 1,11ms et la version sans récursivité de la formule de récurrence met environ 0,49ms.

Je n'ai pas fait de mesure sur la première proposition de Ulmiere parce qu'elle ne peut pas raisonnablement être répétée : c'est contraire à sa logique qui est de conserver des résultats.

Posté par
flight
re : Dérangements et algo 29-11-19 à 16:21

salut

en vba sous excel

Citation :
Sub dérangements()
Dim D() As Variant
Dim k As Double
Dim n As Double

x = 0
D = Array(1, 0)
n = 2
valeur = CInt(InputBox("choix d'une valeur >=2 dont on veut calculer le nombre de dérangements"))
Do
x = 0
k = 1
Do
x = x + combi(n, k) * D(n - k)
k = k + 1
Loop Until n - k < 0
ReDim Preserve D(0 To n)
D(n) = (facto(n) - x)
n = n + 1
Loop Until n = valeur + 1
msgbox D(valeur)
End Sub

Posté par
verdurin
re : Dérangements et algo 29-11-19 à 17:25

Salut flight,
je ne connais pas vba et ( donc ) je comprends mal l'algorithme  que tu utilises.

Peux tu le donner en pseudo-code ?
D'avance merci.

PS : tous les programmes précédemment donnés ( je les ai testés ) donnent
D20=895 014 631 192 902 121.
Es-tu d'accord avec cette valeur ?
Je ne peux pas tester to programme, je n'ai pas excel.

Posté par
flight
re : Dérangements et algo 29-11-19 à 17:42

salut verdurin,  je confirme  bien cette valeuren faisant tourner mon bout de code

Posté par
flight
re : Dérangements et algo 29-11-19 à 17:50

pour faire tourner mon code j'ai du bien sur créer deux autres fonction , une qui calcul les combinaisons et une autre les factorielles ( en pseudo code .. je ne vois pas trop ce que tu veux dire )

Citation :
Function facto(p As Double) As Double
Dim x As Double
x = 1
i = 1
  If p = 0 Then
   facto = 1
   Else
  Do
  x = x * i
  i = i + 1
  Loop Until i = p + 1
  facto = x
  End If
End Function
Function combi(n As Double, p As Double) As Double
combi = facto(n) / (facto(p) * facto(n - p))
End Function

Posté par
LittleFox
re : Dérangements et algo 29-11-19 à 17:57

@verdurin
Évidemment ta formule est efficace. J'ai du mal à voir d'où elle vient par contre Mais elle marche nickel

Si c'est un concours de rapidité d'exécution je propose :

def D(n):
    d, a = 1, -1
    for k in range(1, n+1):
        d *= k
        d += a
        a = -a
    return d

Posté par
Ulmiere
re : Dérangements et algo 29-11-19 à 18:16

Ah ben si c'est la vitesse qu'on cherche, je pense que cette formule est beaucoup plus rapide


def derangement(n):
	u,v = 1,0
	for i in range(1,n):
		u,v = v, i*(u+v)
	return v
	
print derangement(2000)

Posté par
verdurin
re : Dérangements et algo 29-11-19 à 18:44

Je ne pensais pas vraiment à un concours de vitesse.
En fait je m'intéresse plus à l'efficacité « grossière » des formules qu'a leur optimisation.
Mais je vais regarder ça.

@LittleFox,
« ma » formule vient de ce que j'ai une mémoire de poisson rouge.
Et donc je recherche à chaque fois.

Or il est facile de voir comment obtenir un dérangement de n+1 éléments à partir d'une permutation de n éléments :
   -- soit on part d'un dérangement des n premiers éléments et on échange  l'élément supplémentaire avec un des éléments de départ ;
   -- soit on part d'une permutation n'ayant qu'un point fixe et on échange le point fixe avec l'élément supplémentaire.

Ensuite je me souviens d'avoir démontré que la proba d'avoir une permutation sans point fixe tend vers 1/e, ce qui permet de retrouver la formule que tu utilisas.

Posté par
verdurin
re : Dérangements et algo 29-11-19 à 19:48

Bon j'ai fait la course avec timeit pour le calcul de D_{1\,000}
Premier Ulmiere avec 485,9s
Second moi avec 489,8s
Troisième LittleFox avec 510,4s.

Soit des différences assez négligeables.

Posté par
Ulmiere
re : Dérangements et algo 29-11-19 à 20:05

Preum's

Posté par
Ulmiere
re : Dérangements et algo 29-11-19 à 20:09

Et je suis curieux de savoir combien tu trouves pour mon approximation par \left\lfloor\frac{n!}{e}\right\rfloor en remplaçant fact(n) par functools.reduce(lambda x,y:x*y,range(2,n+1),1) ?

Posté par
verdurin
re : Dérangements et algo 29-11-19 à 21:00

J'ai ça :
NameError: name 'functools' is not defined

Posté par
verdurin
re : Dérangements et algo 29-11-19 à 21:06

Mais je pense que ton script était bon car fact(n) n'était calculé qu'une fois, grâce au dictionnaire.
Si on le calcule deux fois ça va pas être bon au niveau temps.

Posté par
alb12
re : Dérangements et algo 30-11-19 à 11:39

la pyramide des 51 premiers.


 \\ \begin{array}{cc}
 \\ 0 & 1 \\
 \\ 1 & 0 \\
 \\ 2 & 1 \\
 \\ 3 & 2 \\
 \\ 4 & 9 \\
 \\ 5 & 44 \\
 \\ 6 & 265 \\
 \\ 7 & 1854 \\
 \\ 8 & 14833 \\
 \\ 9 & 133496 \\
 \\ 10 & 1334961 \\
 \\ 11 & 14684570 \\
 \\ 12 & 176214841 \\
 \\ 13 & 2290792932 \\
 \\ 14 & 32071101049 \\
 \\ 15 & 481066515734 \\
 \\ 16 & 7697064251745 \\
 \\ 17 & 130850092279664 \\
 \\ 18 & 2355301661033953 \\
 \\ 19 & 44750731559645106 \\
 \\ 20 & 895014631192902121 \\
 \\ 21 & 18795307255050944540 \\
 \\ 22 & 413496759611120779881 \\
 \\ 23 & 9510425471055777937262 \\
 \\ 24 & 228250211305338670494289 \\
 \\ 25 & 5706255282633466762357224 \\
 \\ 26 & 148362637348470135821287825 \\
 \\ 27 & 4005791208408693667174771274 \\
 \\ 28 & 112162153835443422680893595673 \\
 \\ 29 & 3252702461227859257745914274516 \\
 \\ 30 & 97581073836835777732377428235481 \\
 \\ 31 & 3025013288941909109703700275299910 \\
 \\ 32 & 96800425246141091510518408809597121 \\
 \\ 33 & 3194414033122656019847107490716704992 \\
 \\ 34 & 108610077126170304674801654684367969729 \\
 \\ 35 & 3801352699415960663618057913952878940514 \\
 \\ 36 & 136848697178974583890250084902303641858505 \\
 \\ 37 & 5063401795622059603939253141385234748764684 \\
 \\ 38 & 192409268233638264949691619372638920453057993 \\
 \\ 39 & 7503961461111892333037973155532917897669261726 \\
 \\ 40 & 300158458444475693321518926221316715906770469041 \\
 \\ 41 & 12306496796223503426182275975073985352177589230680 \\
 \\ 42 & 516872865441387143899655590953107384791458747688561 \\
 \\ 43 & 22225533213979647187685190410983617546032726150608122 \\
 \\ 44 & 977923461415104476258148378083279172025439950626757369 \\
 \\ 45 & 44006555763679701431616677013747562741144797778204081604 \\
 \\ 46 & 2024301565129266265854367142632387886092660697797387753785 \\
 \\ 47 & 95142173561075514495155255703722230646355052796477224427894 \\
 \\ 48 & 4566824330931624695767452273778667071025042534230906772538913 \\
 \\ 49 & 223774392215649610092605161415154686480227084177314431854406736 \\
 \\ 50 & 11188719610782480504630258070757734324011354208865721592720336801
 \\ \end{array}
 \\

 Cliquez pour afficher

Posté par
LittleFox
re : Dérangements et algo 30-11-19 à 19:03

verdurin @ 29-11-2019 à 19:48

Bon j'ai fait la course avec timeit pour le calcul de D_{1\,000}
Premier Ulmiere avec 485,9s
Second moi avec 489,8s
Troisième LittleFox avec 510,4s.

Soit des différences assez négligeables.


Arf



Vous devez être membre accéder à ce service...

Pas encore inscrit ?

1 compte par personne, multi-compte interdit !

Ou identifiez-vous :


Rester sur la page

Désolé, votre version d'Internet Explorer est plus que périmée ! Merci de le mettre à jour ou de télécharger Firefox ou Google Chrome pour utiliser le site. Votre ordinateur vous remerciera !