Art de la programmation informatique Volume 4 : Fascicule 3 en a une tonne qui pourrait correspondre à votre situation particulière mieux que ce que je décris.
Codes gris
Un problème que vous rencontrerez est bien sûr la mémoire et, assez rapidement, vous aurez des problèmes par 20 éléments dans votre ensemble 20 C 3 \= 1140. Et si vous voulez itérer sur l'ensemble, il est préférable d'utiliser un algorithme de code gris modifié afin de ne pas les garder tous en mémoire. Ceux-ci génèrent la combinaison suivante à partir de la précédente et évitent les répétitions. Il en existe de nombreux pour différentes utilisations. Veut-on maximiser les différences entre les combinaisons successives ? minimiser ? et cetera.
Certains des articles originaux décrivant les codes gris :
- Quelques chemins de Hamilton et un algorithme de changement minimal
- Algorithme de génération de combinaisons d'échangeurs adjacents
Voici d'autres documents traitant de ce sujet :
-
Une mise en œuvre efficace de l'algorithme de génération de combinaisons d'échangeurs adjacents de Eades, Hickey et Read (PDF, avec code en Pascal)
- Générateurs combinés
-
Aperçu des codes de Gray combinatoires (PostScript)
- Un algorithme pour les codes Gray
Chase's Twiddle (algorithme)
Phillip J Chase, ` Algorithme 382 : Combinaisons de M objets sur N ' (1970)
L'algorithme de C ...
Index des combinaisons dans l'ordre lexicographique (algorithme Buckles 515)
Vous pouvez également référencer une combinaison par son index (dans l'ordre lexicographique). En réalisant que l'indice doit être une certaine quantité de changement de droite à gauche basée sur l'indice, nous pouvons construire quelque chose qui devrait récupérer une combinaison.
Donc, nous avons un ensemble {1,2,3,4,5,6}... et nous voulons trois éléments. Disons que {1,2,3} nous pouvons dire que la différence entre les éléments est de un et dans l'ordre et minimale. {1,2,4} a un changement et est lexicographiquement numéro 2. Ainsi, le nombre de "changements" dans la dernière place représente un changement dans l'ordre lexicographique. La deuxième place, avec un changement {1,3,4} a un changement mais compte pour plus de changement puisqu'elle est à la deuxième place (proportionnel au nombre d'éléments dans l'ensemble original).
La méthode que j'ai décrite est une déconstruction, car il semble que, de l'ensemble à l'indice, il faille faire l'inverse - ce qui est beaucoup plus délicat. Voici comment Boucles résout le problème. J'ai écrit quelques C pour les calculer J'ai utilisé l'indice des ensembles plutôt qu'une plage de chiffres pour représenter l'ensemble, de sorte que nous travaillons toujours à partir de 0...n. Note :
- Comme les combinaisons ne sont pas ordonnées, {1,3,2} = {1,2,3} -- nous les ordonnons pour être lexicographiques.
- Cette méthode a un 0 implicite pour commencer le jeu pour la première différence.
Index des combinaisons dans l'ordre lexicographique (McCaffrey)
Il y a une autre façon Le concept est plus facile à comprendre et à programmer, mais il ne bénéficie pas des optimisations de Buckles. Heureusement, il ne produit pas non plus de combinaisons dupliquées :
L'ensemble qui maximise où .
Par exemple : 27 = C(6,4) + C(5,3) + C(2,2) + C(1,1)
. Donc, la 27ème combinaison lexicographique de quatre choses est : {1,2,5,6}, ce sont les index de l'ensemble que vous voulez regarder. L'exemple ci-dessous (OCaml), nécessite choose
fonction, de gauche à droite :
(* this will find the [x] combination of a [set] list when taking [k] elements *)
let combination_maccaffery set k x =
(* maximize function -- maximize a that is aCb *)
(* return largest c where c < i and choose(c,i) <= z *)
let rec maximize a b x =
if (choose a b ) <= x then a else maximize (a-1) b x
in
let rec iterate n x i = match i with
| 0 -> []
| i ->
let max = maximize n i x in
max :: iterate n (x - (choose max i)) (i-1)
in
if x < 0 then failwith "errors" else
let idxs = iterate (List.length set) x k in
List.map (List.nth set) (List.sort (-) idxs)
Un petit et simple itérateur de combinaisons
Les deux algorithmes suivants sont fournis à des fins didactiques. Ils implémentent un itérateur et (un plus général) des combinaisons globales de dossiers. Ils sont aussi rapides que possible, ayant la complexité O( n C k ). La consommation de mémoire est limitée par k
.
Nous allons commencer par l'itérateur, qui appellera une fonction fournie par l'utilisateur pour chaque combinaison
let iter_combs n k f =
let rec iter v s j =
if j = k then f v
else for i = s to n - 1 do iter (i::v) (i+1) (j+1) done in
iter [] 0 0
Une version plus générale appellera la fonction fournie par l'utilisateur avec la variable d'état, en partant de l'état initial. Puisque nous devons faire passer l'état entre différents états, nous n'utiliserons pas la boucle for, mais plutôt la récursion,
let fold_combs n k f x =
let rec loop i s c x =
if i < n then
loop (i+1) s c @@
let c = i::c and s = s + 1 and i = i + 1 in
if s < k then loop i s c x else f c x
else x in
loop 0 0 [] x
4 votes
Une préférence pour un langage de programmation ?
9 votes
Comment voulez-vous traiter les lettres en double ?
0 votes
Pas de préférence de langage, je vais le coder en ruby mais une idée générale des algorithmes à utiliser serait bien. Deux lettres de même valeur peuvent exister mais pas la même lettre deux fois.
0 votes
Solution flash as3 stackoverflow.com/questions/4576313/
0 votes
En php, ce qui suit devrait faire l'affaire : stackoverflow.com/questions/4279722/
0 votes
Un peu de ma sagesse Le programme mentionné dans le lien peut être étendu pour résoudre tout problème de nature exponentielle. Voici la structure de base. chamanchindi.blogspot.in/2008/10/
0 votes
Abacus (sur github) une bibliothèque de combinatoire pour Node.JS, Python, PHP, Actionscript (ps je suis l'auteur)
0 votes
@wcm Je n'ai pas trouvé de solution ici pour traiter les lettres en double. Je suis allé de l'avant et j'ai répondu à la question nécessitant les doublons (et nécessitant du C++) : stackoverflow.com/q/29967202/2642059
0 votes
Il y a un bon article convaincant avec ce qui semble être une implémentation efficace en C# ici : msdn.microsoft.com/fr/us/library/aa289166(v=vs.71).aspx