Comptabiliser des permutations en C++

Résolu/Fermé
kjones Messages postés 4 Date d'inscription dimanche 3 juin 2007 Statut Membre Dernière intervention 5 juin 2007 - 4 juin 2007 à 18:15
mamiemando Messages postés 33407 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 29 novembre 2024 - 22 oct. 2008 à 12:06
Bonjour,

Voici un nouveau post plus clair j'éspère. Je cherche à ce qu'un programme en C++ (celui copié en fin de poste par exemple) en plus de faire défiler toutes les permutations d'un ensemble de chiffre, les comptabilisent. Et qu'il m'affiche à la fin 40,320 permutations (pour les cas à 8 chiffres).

Ensuite je cherche des variantes qui consistent à ne comptabiliser que certaines d'entre elles. Par exemple celles qui sont telles que le premier élément est plus grand que le cinquième, le second que le sixième,... le quatrième que le huitième.

Le programme ci-dessous fonctionne pour faire défiler les permutations mais je ne sais comment les comptabiliser.

Merci d'avance pour votre aide

kjones


#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <math.h>
#include <stdlib.h>

/**
Read a number, N, from standard input and print the
permutations.
*/




void print(const int *v, const int size)
{
if (v != 0) {
for (int i = 0; i < size; i++)

{
printf("%4d", v[i] );


}





printf("\n");

} }// print


void swap(int *v, const int i, const int j)
{
int t;
t = v[i];
v[i] = v[j];
v[j] = t;
}


void rotateLeft(int *v, const int start, const int n)
{
int tmp = v[start];
for (int i = start; i < n-1; i++) {
v[i] = v[i+1];
}
v[n-1] = tmp;
} // rotateLeft


void permute(int *v, const int start, const int n)
{

print(v, n);


if (start < n) {
int i, j;
for (i = n-2; i >= start; i--) {
for (j = i + 1; j < n; j++) {
swap(v, i, j);
permute(v, i+1, n);
} // for j
rotateLeft(v, i, n);
} // for i
}
} // permute


void init(int *v, int N)
{
for (int i = 0; i < N; i++) {
v[i] = i+1;
}
} // init


void
main()
{
char buf[80];
int N;
printf("Enter the number of elements: ");
fgets(buf, sizeof(buf), stdin );
sscanf(buf, "%d", &N);

if (N > 0 && N <= 10) {
int *v = new int[N];
init(v, N);
permute(v, 0, N);
delete [] v;
}
}

3 réponses

mamiemando Messages postés 33407 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 29 novembre 2024 7 806
5 juin 2007 à 01:40
La manière la plus simple de programmer ça c'est d'écrire un appel récursif qui va parcourir l'arbre de recherche correspondant à l'ensemble des permutations. L'appel récursif doit passer à ses fils
- la profondeur à laquelle il est rendu (par exemple 3 si j'ai déjà tiré les trois premiers chiffres)
- la profondeur max (par exemple 8 dans le cas des 8 chiffres)
- les chiffres tirés jusqu'ici (par exemple stocké dans un std::vector<short>)

Dans le cas ou les permutations doivent vérifier certaines propriétés, il est possible de définir des coupes qui éviteront de poursuivre l'appel récursif vers des feuilles qui ne serviront de toute façon à rien.

Je ne suis pas sûre d'avoir compris ce que tu comptais mais si ce sont tous les nombres de K chiffres, où chaque chiffre est distinct et prend une valeur comprise entre 0 et 9 ça donne ce genre de chose (ici K=3)
#include <vector>
#include <iostream>
#include <cassert>

void f(
    unsigned prof,              // la profondeur courante (nombre de chiffre choisis)
    const unsigned & prof_max,  // la profondeur max (nombre de chiffre à choisir)
    std::vector<short> perm,    // la permutation courante
    std::vector<bool> marked,   // les nombres utilisés
    unsigned & compteur         // le nombre de permutations rencontrées
){
    if (prof < prof_max){
        for(unsigned i=0;i<=9;++i){
            if (marked[i]) continue;
            std::vector<short> perm_suivant = perm;
            perm_suivant.push_back(i);
            std::vector<bool> marked_suivant = marked;
            marked_suivant[i] = true;
            f(prof+1,prof_max,perm_suivant,marked_suivant,compteur);
        }
    }else{ // le nombre a la taille voulue
        for(unsigned i=0;i<perm.size();++i) std::cout << perm[i];
        std::cout << std::endl;
        ++compteur;
    }
}

void perm(const unsigned & prof_max){
    assert(prof_max<=10);
    std::vector<short> perm0;
    std::vector<bool> marked0(10,false);
    unsigned compteur = 0; // partagé par tous les appels recursifs
    f(0,prof_max,perm0,marked0,compteur);
    std::cout << "compteur = " << compteur << std::endl;
}

int main(){
    perm(3);
    return 0;
}

Ce qui donne
(mando@aldur) (~) $ ./a.out
012
013
014
015
016
017
018
019
021
023
024
025
...
975
976
978
980
981
982
983
984
985
986
987
compteur = 720

Tu as donc bien toutes les permutations de taille 3 d'un ensemble à 10 éléments (valeurs de 0 à 9). C'est ce que tu voulais ?

Bonne chance
1
kjones Messages postés 4 Date d'inscription dimanche 3 juin 2007 Statut Membre Dernière intervention 5 juin 2007
5 juin 2007 à 09:17
Bonjour,

En fait ça marche bien! Merci!

Kjones
-1
Bonjour,

je voudrais m'inspirer de ton programme qui est très rapide pour essayer de faire une liste
de permutations avec répetitions.
Je m'explique:
étant donnés un nombre n et un alphabet Z constitué seulement de 4 lettres tel que Z= {A,T,G,C},
produire toutes les chaines de caractères de longueur n=10 pris parmis l'alphabet Z.

Un exemple avec Z = {A, C} et n = 3 nous donnerait un total de 9 motifs:
aaa
aac
aca
caa
acc
cac
cca
ccc

Pour augmenter la rapidité du code on pourrait aussi assigner à chaque lettre A,T,G,C une valeur binaire:
00,01,10,11.
Puis ensuite refaire la reconversion en lettres après les boucles de traitement.

On a alors 2^(2n) motifs en binaire et 4^n motifs en lettres après conversion.

Tu peux m'aider STP ?
0
mamiemando Messages postés 33407 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 29 novembre 2024 7 806
21 oct. 2008 à 19:52
Oui mais ouvre un nouveau sujet en faisant référence à celui-ci pour maintenir la clarté de ce fil de discussion.
-1
mslider Messages postés 109 Date d'inscription jeudi 21 octobre 2004 Statut Membre Dernière intervention 7 mars 2010
21 oct. 2008 à 20:54
je viens de le faire, voir le sujet "Permutations avec répétitions en C++"
-1
mamiemando Messages postés 33407 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 29 novembre 2024 7 806
22 oct. 2008 à 12:06
Parfait je vais y jeter un oeil tout à l'heure
-1