Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentes Révision précédente | Dernière révision Les deux révisions suivantes | ||
combinatoire [2009/12/29 10:15] tyrtamos |
combinatoire [2010/01/09 09:18] tyrtamos |
||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
- | ====== | + | ====== |
**En cours de modification! (20/ | **En cours de modification! (20/ | ||
- | ===== Permutations ===== | + | La page relative à l' |
- | Référence pour la définition: | ||
- | Par exemple, les permutations de trois objets distincts A, B et C sont: ABC, ACB, BAC, BCA, CAB, CBA. | ||
- | ==== Calcul du nombre de permutations ==== | ||
- | === Nombre de permutations sans répétition === | ||
- | Dans l' | ||
- | On va donc reprendre le code de la factorielle dans sa version non récursive: | ||
- | <code python> | + | ===== Permutations ===== |
- | def permut(n): | + | |
- | """ | + | |
- | x = 1 | + | |
- | for i in xrange(2, n[0]+1): | + | |
- | x *= i | + | |
- | return x | + | |
- | </ | + | |
- | Exemple | + | Soit une liste d'objets [1,2,3], on veut savoir les présenter de toutes les façons possibles: %%[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]%%, et on veut savoir combien il y en a. |
- | <code python> | + | Référence externe |
- | print permut(3) | + | |
- | 6 | + | |
- | </ | + | |
- | + | ||
- | === Nombre de permutations avec répétition === | + | |
- | + | ||
- | Là, on a un objet plus complexe, composés d' | + | |
- | + | ||
- | Par exemple: [1, | + | |
- | + | ||
- | Ainsi, il y aura permut(8)=40320 façons de présenter cette liste, mais certaines seront identiques! | + | |
- | + | ||
- | On veut donc calculer ici le nombre de permutations //en ne comptant qu'une seule fois les permutations identiques// | + | |
- | + | ||
- | Il suffit de diviser le nombre total de permutations par chacune des factorielles des répétitions. | + | |
- | + | ||
- | Pour reprendre l' | + | |
- | + | ||
- | Voilà le code qui fait ça. Pour le lancer, on met comme paramètre le nombre d' | + | |
- | + | ||
- | <code python> | + | |
- | def permut(n, r=[]): | + | |
- | """ | + | |
- | r est la liste des éventuelles répétitions rencontrées dans les n objets | + | |
- | | + | |
- | """ | + | |
- | x = 1 | + | |
- | for i in xrange(2, n+1): | + | |
- | x *= i | + | |
- | for m in r: | + | |
- | y = 1 | + | |
- | for i in xrange(2, m+1): | + | |
- | y *= i | + | |
- | x //= y | + | |
- | return x | + | |
- | </ | + | |
- | + | ||
- | Exemple: | + | |
- | + | ||
- | <code python> | + | |
- | # objet de 8 éléments avec le 2 mis 2 fois et le 5 mis 3 fois | + | |
- | seq = [1, | + | |
- | + | ||
- | # nombre total de permutation sans répétition | + | |
- | print permut(len(seq)) | + | |
- | 40320 | + | |
- | + | ||
- | # nombre de permutations avec répétitions | + | |
- | # (= en ne comptant qu'une seule fois les permutations identiques) | + | |
- | print permut(len(seq), | + | |
- | 3360 | + | |
- | </ | + | |
- | + | ||
- | Bien entendu, on peut calculer automatiquement la liste des répétitions des objets dans la liste des objets. | + | |
- | + | ||
- | Par exemple comme suit (code très auto-commenté!): | + | |
- | + | ||
- | <code python> | + | |
- | def repetelem(seq): | + | |
- | """ | + | |
- | r = [] # pour enregistrer les éléments déjà traités | + | |
- | d = [] # pour enregistrer le nombre de répétitions > 1 des éléments | + | |
- | for elem in seq: | + | |
- | if (elem not in r): # si l' | + | |
- | r.append(elem) | + | |
- | x = seq.count(elem) | + | |
- | if x> | + | |
- | d.append(x) | + | |
- | return d # on renvoie | + | |
- | </ | + | |
- | + | ||
- | Exemple d' | + | |
- | + | ||
- | <code python> | + | |
- | seq = [1, | + | |
- | + | ||
- | print repetelem(seq) | + | |
- | [2, 3, 6] | + | |
- | + | ||
- | print permut(len(seq)) | + | |
- | 87178291200 | + | |
- | + | ||
- | print permut(len(seq), | + | |
- | 10090080 | + | |
- | </ | + | |
- | + | ||
- | S'il n'y a qu'une seule de ces 2 fonctions permut() à retenir (sans ou avec répétition), | + | |
- | + | ||
- | * s'il n'y a qu'un seul argument, c'est qu'on n'a pas de répétition (ou qu'on n'en tient pas compte). | + | |
- | + | ||
- | * dans le cas contraire, il suffit d' | + | |
- | + | ||
- | ==== Liste des permutations de chaînes de caractères présentées dans une liste ==== | + | |
- | + | ||
- | On sait maintenant calculer le **nombre** de permutations, | + | |
- | + | ||
- | Par exemple: trouver toutes les permutations possibles de [1, 2, 3], c'est à dire: [1, 2, 3], [1, 3, 2], [2, 3, 1], [2, 1, 3], [3, 1, 2], [3, 2, 1] | + | |
- | + | ||
- | Ça pourrait, bien sûr, être une liste de n' | + | |
- | + | ||
- | Sont présentés ci-dessous un code non-récursif (que je conseille) et un code récursif. Ils sont basés sur le même principe: des rotations des éléments qui se trouvent entre l' | + | |
- | + | ||
- | Par exemple pour seq=[1, | + | |
- | + | ||
- | * pour k=0, on aura les rotations: [1,2,3,4], [2,3,4,1], [3,4,1,2], [4,1,2,3] | + | |
- | + | ||
- | * pour k=1, on aura les rotations: [1,2,3,4], [1,3,4,2], [1,4,2,3] | + | |
- | + | ||
- | * pour k=2, on aura les rotations: [1,2,3,4], [1,2,4,3] | + | |
- | + | ||
- | * pour k=3, c'est à dire pour k=len(seq)-1, | + | |
- | + | ||
- | Pour chaque k, il y a len(seq)-k rotations en tout (c'est à dire len(seq)-k-1 en plus du seq initial) | + | |
- | + | ||
- | Pour faire une rotation à partir de l' | + | |
- | + | ||
- | \\ | + | |
- | Bon. Dans vos essais, soyez raisonnables: | + | |
- | + | ||
- | === Code non récursif === | + | |
- | + | ||
- | Le code non-récursif est ici assez concis et très rapide (2 à 3 fois plus que le code récursif). | + | |
- | + | ||
- | Voilà le code: | + | |
- | + | ||
- | <code python> | + | |
- | def permutliste(seq, | + | |
- | """ | + | |
- | si er=True: élimination des répétitions quand seq en a (ex: [1,2,2] | + | |
- | """ | + | |
- | p = [seq] | + | |
- | n = len(seq) | + | |
- | for k in xrange(0, | + | |
- | for i in xrange(0, len(p)): | + | |
- | z = p[i][:] | + | |
- | for c in xrange(0, | + | |
- | z.append(z.pop(k)) | + | |
- | if er==False or (z not in p): | + | |
- | p.append(z[: | + | |
- | return p | + | |
- | </ | + | |
- | + | ||
- | On peut améliorer sa présentation avec un tri (avec p.sort() ou sorted(p) par ex.). | + | |
- | + | ||
- | On a tenu compte d'un 2ème argument ici pour éviter les répétitions. En effet, quand la liste initiale seq contient des éléments qui se répètent, le résultat contiendra plusieurs listes identiques. Pour que ces listes identiques ne soient comptées qu'une seule fois, il suffit d' | + | |
- | + | ||
- | Exemple d' | + | |
- | + | ||
- | <code python> | + | |
- | seq = [1,2,3] | + | |
- | print permutliste(seq) | + | |
- | [[1, 2, 3], [1, 3, 2], [2, 3, 1], [2, 1, 3], [3, 1, 2], [3, 2, 1]] | + | |
- | + | ||
- | seq = [1,2,2] | + | |
- | print permutliste(seq) | + | |
- | [[1, 2, 2], [2, 2, 1], [2, 1, 2], [1, 2, 2], [2, 1, 2], [2, 2, 1]] | + | |
- | + | ||
- | seq = [1,2,2] | + | |
- | print permutliste(seq, | + | |
- | [[1, 2, 2], [2, 2, 1], [2, 1, 2]] | + | |
- | </ | + | |
- | + | ||
- | + | ||
- | === Code récursif === | + | |
- | + | ||
- | Voilà le code récursif: | + | |
- | + | ||
- | <code python> | + | |
- | def permutliste(seq, | + | |
- | """ | + | |
- | si er=True: élimination des répétitions quand seq en a (ex: [1,2,2] | + | |
- | """ | + | |
- | n = len(seq) | + | |
- | if k == n-1: | + | |
- | return [] | + | |
- | p = [] | + | |
- | z = seq[:] | + | |
- | for c in xrange(0, n-k): | + | |
- | if er==False or (z not in p): | + | |
- | p.append(z[: | + | |
- | p.extend(permutliste(z, | + | |
- | z.append(z.pop(k)) | + | |
- | return p | + | |
- | </ | + | |
- | + | ||
- | On ne donne jamais le 3ème argument k qui n'est utilisé que comme variable interne. | + | |
- | + | ||
- | Au lancement de la fonction, permutliste([1, | + | |
- | + | ||
- | Ce code donne bien entendu les mêmes résultats que le code non-récursif. | + | |
- | + | ||
- | Si vous voulez un résultat plus " | + | |
- | + | ||
- | Et pour éviter les répétitions au cas où des éléments se répètent dans la liste seq, on ajoute simplement l' | + | |
- | + | ||
- | + | ||
- | ==== Liste des permutations des caractères d'une chaîne de caractères ==== | + | |
- | + | ||
- | Même principe que précédemment, | + | |
- | + | ||
- | Utilisation possible (entre autres): recherche d' | + | |
- | + | ||
- | La solution de codage utilise l'une des fonctions précédentes qui traite les listes (Python est vraiment doué pour manipuler des listes!): | + | |
- | + | ||
- | <code python> | + | |
- | def permutchaine(ch, | + | |
- | """ | + | |
- | avec er=True pour éviter les répétitions quand ch en a (ex: ' | + | |
- | """ | + | |
- | return ['' | + | |
- | </ | + | |
- | + | ||
- | <code python> | + | |
- | # exemples d' | + | |
- | print permutchaine(" | + | |
- | </ | + | |
- | + | ||
- | Si vous voulez que la chaîne résultat soit rangée selon l' | + | |
- | + | ||
- | <code python> | + | |
- | R=permutchaine(" | + | |
- | print R # affiche: [' | + | |
- | R.sort() | + | |
- | print R # affiche: [' | + | |
- | R.reverse() | + | |
- | print R # affiche: [' | + | |
- | </ | + | |
- | + | ||
- | Il y a une utilisation très intéressante de permutchaine(): | + | |
- | + | ||
- | Par exemple: | + | |
- | + | ||
- | <code python> | + | |
- | print sorted(permutchaine(' | + | |
- | </ | + | |
- | + | ||
- | Ce qui affichera (en une seule ligne): | + | |
- | + | ||
- | <code python> | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ' | + | |
- | ]</ | + | |
+ | Page du site qui traite des permutations: | ||
===== Ensemble des parties d'un ensemble ===== | ===== Ensemble des parties d'un ensemble ===== | ||
- | Il s'agit ici de tous les sous-ensembles qu'on peut construire à partir d'un ensemble d' | ||
- | |||
- | Par exemple: [1, | ||
- | |||
- | Pour la théorie, voir ici (entre autres): [[http:// | ||
- | |||
- | ==== Nombre des parties d'un ensemble ==== | ||
- | |||
- | Combien il en a? => si l' | ||
- | |||
- | <code python> | ||
- | def parties(n): | ||
- | return 2**n | ||
- | </ | ||
- | |||
- | En fait, on verra après (chapitre sur les combinaisons) qu'on peut le retrouver d'une autre façon: le nombre total de sous-ensemble est égal à la somme des combinaisons: | ||
- | |||
- | < | ||
- | |||
- | Essayons avec un ensemble de 3 éléments: | ||
- | |||
- | * Combinaison de 3 objets pris de 0 à 0 => 1 ([]) | ||
- | * Combinaison de 3 objets pris de 1 à 1 => 3 ([1], [2], [3]) | ||
- | * Combinaison de 3 objets pris de 2 à 2 => 3 ([1, 2], [1, 3], [2, 3]) | ||
- | * Combinaison de 3 objets pris de 3 à 3 => 1 ([1, 2, 3]) | ||
- | |||
- | Total = 8 = %%2**3%% | ||
- | |||
- | ==== Liste des parties d'un ensemble composé d'une liste ==== | ||
- | |||
- | On voudrait maintenant construire automatiquement une telle liste dans le cas général. Comment on fait? | ||
- | |||
- | Pour résoudre ce genre de problème, il y a une solution que j'aime bien, qui n'est pas trop complexe à comprendre et qui n'est pas récursive: il s'agit de s' | ||
- | |||
- | Avec une liste composée de n éléments, on va compter de 0 à %%2**n-1%%, et pour chaque valeur de ce compteur, on va placer un élément de la liste à chaque 1 qu'on aura dans la représentation binaire du compteur. | ||
- | |||
- | Exemple: | ||
- | |||
- | liste = [' | ||
- | |||
- | On va donc compter de 0 à %%2**3-1=7%% | ||
- | |||
- | < | ||
- | 0 | ||
- | 1 | ||
- | 2 | ||
- | 3 | ||
- | 4 | ||
- | 5 | ||
- | 6 | ||
- | 7 | ||
- | </ | ||
- | |||
- | On voit bien dans cet exemple: pour une valeur du compteur, s'il y a un ' | ||
- | |||
- | Et pour n' | ||
- | |||
- | Voilà un code qui fait tout cela. l' | ||
- | |||
- | <code python> | ||
- | def partiesliste(seq): | ||
- | p = [] | ||
- | i, imax = 0, 2**len(seq)-1 | ||
- | while i <= imax: | ||
- | s = [] | ||
- | j, jmax = 0, len(seq)-1 | ||
- | while j <= jmax: | ||
- | if (i>> | ||
- | s.append(seq[j]) | ||
- | j += 1 | ||
- | p.append(s) | ||
- | i += 1 | ||
- | return p | ||
- | </ | ||
- | |||
- | Vous voyez comment on teste s'il y a un ' | ||
- | |||
- | Par exemple: i=8 => ' | ||
- | |||
- | Exemple d' | ||
- | |||
- | <code python> | ||
- | seq = [1,2,3] | ||
- | |||
- | print partiesliste(seq) | ||
- | [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]] | ||
- | </ | ||
- | |||
- | On se servira de ce code légèrement modifié pour calculer la liste des combinaisons, | ||
- | |||
- | ==== Liste des parties d'un ensemble composé d'une chaine de caractères ==== | ||
- | |||
- | On a ici une chaine de caractère, et on veut obtenir la liste de toutes les parties de l' | ||
- | |||
- | Par exemple: %%" | ||
- | |||
- | On va utiliser la fonction qui traite les listes: | ||
- | |||
- | <code python> | ||
- | def partieschaine(ch): | ||
- | """ | ||
- | return ['' | ||
- | </ | ||
- | |||
- | Exemple d' | ||
- | |||
- | <code python> | ||
- | print partieschaine(" | ||
- | ['', | ||
- | </ | ||
===== Combinaisons ===== | ===== Combinaisons ===== | ||
- | Voir pour la définition (entre autres): [[http:// | ||
- | |||
- | Par exemple, on cherche les combinaisons de 3 objets pris 2 à 2: %%[' | ||
- | |||
- | Contrairement aux permutations, | ||
- | |||
- | ==== Nombre de combinaisons de n objets pris k à k ==== | ||
- | |||
- | Le calcul du nombre de combinaisons de n objets pris k à k est donnée par la formule: | ||
- | |||
- | < | ||
- | |||
- | Soit, en Python (si fact(n)=factorielle de n): | ||
- | |||
- | Cnk = fact(n)/ | ||
- | |||
- | === Solution non-récursive === | ||
- | |||
- | Puisque nous sommes sous Python qui sait calculer des nombres entiers énormes, nous pouvons utiliser brutalement les factorielles en prenant la fonction fact(n) présentée ailleurs sur ce site: | ||
- | |||
- | <code python> | ||
- | combin = lambda n,k: fact(n)// | ||
- | </ | ||
- | |||
- | Il est difficile de faire plus simple... | ||
- | |||
- | Mais le plus efficace est quand même le suivant, qui calcule progressivement le résultat sans calculer des grands nombres: | ||
- | |||
- | <code python> | ||
- | def combin(n, k): | ||
- | """ | ||
- | if k > n//2: | ||
- | k = n-k | ||
- | x = 1 | ||
- | y = 1 | ||
- | i = n-k+1 | ||
- | while i <= n: | ||
- | x = (x*i)//y | ||
- | y += 1 | ||
- | i += 1 | ||
- | return x | ||
- | </ | ||
- | |||
- | Attention à ne pas utiliser dans ce code le raccourci habituel %%x *= i//y%%, car il faut que la multiplication ait lieu **avant** la division entière, sinon celle-ci ne tombe pas juste, et le résultat final est faux. | ||
- | |||
- | Pour que cette fonction soit utilisable avec de très grands nombres, j'ai tenu compte des points suivants: | ||
- | |||
- | * il faut utiliser while au lieu de for, car xrange() ne supporte pas les types ' | ||
- | |||
- | * si %%k> | ||
- | |||
- | |||
- | Exemple d' | ||
- | |||
- | <code python> | ||
- | print combin(3, | ||
- | print combin(50, | ||
- | </ | ||
- | |||
- | Ce code est très rapide: par exemple, le nombre de combinaisons de 100000 (cent mille) objets pris 100 à 100 donne en moins d' | ||
- | |||
- | < | ||
- | 1019745118068508355816143175813864936340849501519143871777101229221311704707028464150801159851819171048218667041957300317610197834902713500555020173048960798706784754817501032954266210951200883251987669862675631847360156537041811409331039637713779759572781307343494274990819880664139309679429703675390591419799883108282575404188096902252124000 | ||
- | </ | ||
- | |||
- | === Solution récursive === | ||
- | |||
- | La solution récursive est particulièrement simple: | ||
- | |||
- | <code python> | ||
- | def combin(n, | ||
- | """ | ||
- | if k==0 or k==n: | ||
- | return 1 | ||
- | return combin(n-1, k-1) + combin(n-1, | ||
- | </ | ||
- | |||
- | Malheureusement, | ||
- | |||
- | Pour mémoire, citons une version non-récursive qui imite assez bien la version récursive en gérant directement la pile des appels: | ||
- | |||
- | <code python> | ||
- | def combin(n, k): | ||
- | """ | ||
- | pile = [[n,k]] | ||
- | r = 0 | ||
- | while len(pile)> | ||
- | i, j = pile.pop(-1) | ||
- | if j==0 or i==j: | ||
- | r += 1 | ||
- | else: | ||
- | pile.append([i-1, | ||
- | pile.append([i-1, | ||
- | return r | ||
- | </ | ||
- | |||
- | Le principe n'est pas très compliqué. On utilise une pile pour conserver les combinaisons en attente de résolution, | ||
- | |||
- | - initialement, | ||
- | |||
- | - A chaque boucle while, on dépile le dernier couple [i,j]. Les 2 seuls couples dont on connait la valeur correspondent à combin(x, | ||
- | |||
- | La boucle s' | ||
- | |||
- | Voyons cela sur un exemple. On ajoute juste après le while la ligne suivante (avec la bonne indentation): | ||
- | |||
- | <code python> | ||
- | print r, pile | ||
- | </ | ||
- | |||
- | et on lance l' | ||
- | |||
- | <code python> | ||
- | print combin(5,3) | ||
- | </ | ||
- | |||
- | Ce qui affiche: | ||
- | |||
- | < | ||
- | 0 [[5, 3]] | ||
- | 0 [[4, 2], [4, 3]] | ||
- | 0 [[4, 2], [3, 2], [3, 3]] | ||
- | 1 [[4, 2], [3, 2]] | ||
- | 1 [[4, 2], [2, 1], [2, 2]] | ||
- | 2 [[4, 2], [2, 1]] | ||
- | 2 [[4, 2], [1, 0], [1, 1]] | ||
- | 3 [[4, 2], [1, 0]] | ||
- | 4 [[4, 2]] | ||
- | 4 [[3, 1], [3, 2]] | ||
- | 4 [[3, 1], [2, 1], [2, 2]] | ||
- | 5 [[3, 1], [2, 1]] | ||
- | 5 [[3, 1], [1, 0], [1, 1]] | ||
- | 6 [[3, 1], [1, 0]] | ||
- | 7 [[3, 1]] | ||
- | 7 [[2, 0], [2, 1]] | ||
- | 7 [[2, 0], [1, 0], [1, 1]] | ||
- | 8 [[2, 0], [1, 0]] | ||
- | 9 [[2, 0]] | ||
- | 10 | ||
- | </ | ||
- | |||
- | On voit bien que r n'est incrémentée (et la pile dépilée) que lorsque la combinaison finale est [0,x] ou [x,x]. | ||
- | |||
- | Le résultat final est ok, mais par rapport au code non-récursif précédent, | ||
- | |||
- | A ne conserver que pour des considérations théoriques. | ||
- | |||
- | ==== Liste des combinaisons d'une liste de n objets pris k à k ==== | ||
- | |||
- | Par exemple, nous voulons trouver la liste de toutes les combinaisons de de 3 objets pris 2 à 2, qui est: %%[1,2,3]%% => %%[[1,2], [1,3], [2,3]]%% | ||
- | |||
- | Nous allons reprendre tout simplement le principe de " | ||
- | |||
- | Cela donnera comme code: | ||
- | |||
- | <code python> | ||
- | def combinliste(seq, | ||
- | p = [] | ||
- | i, imax = 0, 2**len(seq)-1 | ||
- | while i<=imax: | ||
- | s = [] | ||
- | j, jmax = 0, len(seq)-1 | ||
- | while j<=jmax: | ||
- | if (i>> | ||
- | s.append(seq[j]) | ||
- | j += 1 | ||
- | if len(s)==k: | ||
- | p.append(s) | ||
- | i += 1 | ||
- | return p | ||
- | </ | ||
- | |||
- | Exemples d' | ||
- | |||
- | <code python> | ||
- | print combinliste([' | ||
- | print combinliste([' | ||
- | </ | ||
- | |||
- | Comme vu précédemment, | ||
- | |||
- | ==== Liste des combinaisons d'une chaine de n caractères pris k à k ==== | ||
- | |||
- | C'est le même principe, à part que la donnée est une chaîne de caractères, | ||
- | |||
- | La solution la plus simple est d' | ||
- | |||
- | <code python> | ||
- | def combinchaine(ch, | ||
- | return ['' | ||
- | </ | ||
- | |||
- | Exemple d' | ||
- | |||
- | <code python> | ||
- | print combinchaine(' | ||
- | [' | ||
- | </ | ||
- | |||
- | ==== Combinaisons avec répétition ==== | ||
- | |||
- | Jusqu' | ||
- | |||
- | Quand l'un des éléments au moins apparait plusieurs fois dans la liste des objets, il y a deux effets dans la liste des combinaisons. | ||
- | |||
- | Par exemple dans les combinaisons de [1,2,2] pris 2 à 2 qui donne [[1, 2], [1, 2], [2, 2]]: | ||
- | |||
- | * présence de séquences contenant des répétitions. Ici: [2,2] | ||
- | |||
- | * présence de séquences identiques. Ici: [1,2] et [1,2]. | ||
- | |||
- | Que peut-on faire avec ça? Tout dépendra de ce qu'on obtenir par rapport au problème à résoudre: | ||
- | |||
- | * on n'a pas de répétition dans la liste des objets de départ mais on en veut dans les résultats | ||
- | |||
- | * on a des répétitions dans la liste des objets de départ et on veut éliminer ses effets dans les résultats | ||
- | |||
- | Voyons ces 2 cas. | ||
- | |||
- | **__On veut des combinaisons avec répétition__** | ||
- | |||
- | Par exemple: on a [1,2,3], mais on veut obtenir une combinaison de ces 3 objets pris 2 à 2 **avec répétition** comme: %%[[1, 1], [1, 2], [2, 2], [1, 3], [2, 3], [3, 3]]%% | ||
- | |||
- | Il suffit de transformer la liste de départ en répétant chaque élément autant de fois que la combinaison cherchée le demande (ici, 2): [1,2,3] devient donc [1, | ||
- | |||
- | Combien cela va-t-il donner de séquence dans les résultats? Cela en donnera: | ||
- | |||
- | < | ||
- | |||
- | n étant le nombre d' | ||
- | |||
- | <code python> | ||
- | Combin(3+2-1, | ||
- | 6 | ||
- | </ | ||
- | |||
- | Pour calculer la liste de ces combinaisons avec répétition, | ||
- | |||
- | <code python> | ||
- | def repet(seq, m=-1): | ||
- | """ | ||
- | si m==0, renvoie seq sans rien changer | ||
- | si m==-1 (défaut), chaque élément de seq apparait len(seq) fois | ||
- | """ | ||
- | if m == 0: | ||
- | return seq[:] | ||
- | if m == -1: | ||
- | m = len(seq) | ||
- | r = [] | ||
- | for elem in seq: | ||
- | if elem not in r: | ||
- | for k in xrange(0, | ||
- | r.append(elem) | ||
- | return r | ||
- | </ | ||
- | |||
- | Avec cette fonction, la liste d' | ||
- | |||
- | On peut faire la même chose avec une chaine de caractère. Par exemple, on veut la liste des mots de 3 lettres de l' | ||
- | |||
- | <code python> | ||
- | ch = '' | ||
- | </ | ||
- | |||
- | |||
- | |||
- | |||
- | ===== Arrangement ===== | ||
- | |||
- | Référence pour la définition: | ||
- | |||
- | Par exemple, l' | ||
- | |||
- | Vous voyez la principale différence avec les combinaisons. Pour les combinaisons, | ||
- | |||
- | ==== Calcul du nombre d' | ||
- | |||
- | Il y a 6 arrangements, | ||
- | |||
- | < | ||
- | |||
- | Ou, en Python (si fact(n) est la factorielle de n) | ||
- | |||
- | Ank = fact(n)/ | ||
- | |||
- | Ce qui donne le code suivant: | ||
- | |||
- | <code python> | ||
- | def arrang(n, k): | ||
- | """ | ||
- | if k>n: | ||
- | return 0 | ||
- | x = 1 | ||
- | i = n-k+1 | ||
- | while i <= n: | ||
- | x *= i | ||
- | i += 1 | ||
- | return x | ||
- | </ | ||
- | |||
- | Exemple d' | ||
- | |||
- | <code python> | ||
- | print arrang(5,3) | ||
- | 60 | ||
- | </ | ||
- | |||
- | Vous noterez le cas k>n qui est prévu dans la définition mathématique, | ||
- | |||
- | ==== Liste des arrangements | ||
- | |||
- | Comme nous savons trouver la liste des combinaisons, | ||
- | |||
- | Par exemple, la liste des combinaisons de 5 objets [' | ||
- | |||
- | %%[[' | ||
- | |||
- | On constate que chaque combinaison trouvée est unique. | ||
- | |||
- | Par exemple %%[' | ||
- | |||
- | Mais pour les arrangements, | ||
- | |||
- | Voici le code correspondant. Il est directement issu de combinliste(), | ||
- | |||
- | <code python> | ||
- | def arrangliste(seq, | ||
- | """ | ||
- | p = [] | ||
- | i, imax = 0, 2**len(seq)-1 | ||
- | while i<=imax: | ||
- | s = [] | ||
- | j, jmax = 0, len(seq)-1 | ||
- | while j<=jmax: | ||
- | if (i>> | ||
- | s.append(seq[j]) | ||
- | j += 1 | ||
- | if len(s)==k: | ||
- | v = permutliste(s) | ||
- | p.extend(v) | ||
- | i += 1 | ||
- | return p | ||
- | </ | ||
- | |||
- | Exemple d' | ||
- | <code python> | + | ===== Arrangements ===== |
- | print arrangliste([' | + | |
- | </ | + | |
- | ==== Liste des arrangements d'une chaine de n caractères pris k à k ==== | ||
- | C'est le même principe, à part que la donnée est une chaîne, et qu'on cherche tous les arrangements de k caractères de cette chaîne de longueur n. | ||
- | La solution la plus simple est d' | ||
- | <code python> | ||
- | def arrangchaine(ch, | ||
- | return ['' | ||
- | </ | ||
- | Exemple d' | ||
- | <code python> | ||
- | print arrangchaine(' | ||
- | </ | ||
- | \\ | ||
- | Amusez-vous bien! | ||
< | < |