Rechercher : dans
Par :

Permutations avec répétitions en C++

Dernière réponse le 31 mar 2009 à 12:49:28 mslider, le 21 oct 2008 à 20:52:47 
 Signaler ce message aux modérateurs

Bonjour,

je voudrais m'inspirer du programme de mamiemando (voir le sujet Comptabiliser des permutations en C++ dans ce même forum) 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.

Pouvez-vous m'aider SVP ?

Configuration: Windows XP
Internet Explorer 6.0

Meilleures réponses pour « Permutations avec répétitions en C++ » dans :
La compilation et les modules en C et en C++ VoirCet article a pour vocation d'introduire les notions de bases de la compilation en C et en C++ et de la programmation modulaire. Il permet de mieux comprendre les messages d'erreur du compilateur. Les notions abordées ici sont indépendantes du...
3D Secure / Verified by Visa / SecureCode: Qu'est-ce que c'est ? VoirDepuis octobre 2008, les banques et commerçants en ligne ont commencé à adopter le système 3DSecure pour les paiements sur Internet. Qu'est-ce que c'est ? 3DSecure est appelé "Verified by Visa" chez Visa, et "SecureCode" chez Mastercard. (Les logos...
[Langage C] C/C++ Erreur de segmentation VoirQu'est ce qu'une erreur de segmentation Vous êtes en train de développer une application sous Linux en C/C++. Tout va bien, ça compile, les oiseaux chantent. Donc vous lancez votre application pour la tester. Et vous obtenez l'un de ces deux...
Télécharger Visual C++ Express VoirVisual C++ Express est une version "gratuite" et allégée de Visual Studio ; l'utilisation requiert l'inscription sur le site de Microsoft. Cet environnement de développement permet de créer des application Win32 ou du .NET C.
Langage C++ - Les types de données VoirLes types de données Les données manipulées en langage C++, comme en langage C, sont typées, c'est-à-dire que pour chaque donnée que l'on utilise (dans les variables par exemple) il faut préciser le type de donnée, ce qui permet de connaître...
Les chaînes de caractères en C++ VoirQu'est-ce qu'une chaîne de caractères ? Une chaîne de caractères (appelée string en anglais) est une suite de caractères, c'est-à-dire un ensemble de symboles faisant partie du jeu de caractères, défini par le code ASCII. En langage C++, une...
Langage C - Les types de données VoirLes types de données Les données manipulées en langage C sont typées, c'est-à-dire que pour chaque donnée que l'on utilise (dans les variables par exemple) il faut préciser le type de donnée, ce qui permet de connaître l'occupation mémoire (le...

1

mslider, le 22 oct 2008 à 12:54:57

J'ai oublié: dans le cas de l'énoncé ci-dessus on devrait donc obtenir avec n=10 et Z = {A,T,G,C}
4^10=1048576 possibilités, allant de AAAAAAAAAA à TTTTTTTTTT. Je pense que pour n>20 la combinatoire devient énorme et le programme quel qu'il soit prendrait énormément de temps de calcul.

Répondre à mslider

2

mslider, le 22 oct 2008 à 21:41:46

[code]

#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=1;i<=4;++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<=4);
std::vector<short> perm0;
std::vector<bool> marked0(4,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(4);
return 0;
}
[code]

je comprend pas pourquoi ce code me renvoit une dernière ligne 4444 et pas les lignes 1111,2222,3333 !

Répondre à mslider

3

mamiemando, le 23 oct 2008 à 12:46:01

Pour les personnes qui tomberaient sur ce fil, je précise que le programme évoqué par mslider est ici :
http://www.commentcamarche.net/forum/affich 3075042 comptabiliser des permutations en c?#1

Tu peux coder en binaire mais ça ne change pas grand chose au problème, à la limite la conversion binaires ou entiers vers lettres peut se faire simplement au niveau de la fonction d'affichage. En soit vu que la structure n'es jamais stockée en mémoire et qu'il n'y a que n caractères avec n très petit, autant travailler avec des entiers et reprendre comme tu l'as fait le programme que j'ai écrit.

Pour répondre à ta question, le vecteur marked vérifie dans le programme initial qu'un nombre n'a pas été déjà utilisé à ce niveau :

if (marked[i]) continue;

Ainsi, cette ligne interdit d'avoir deux fois le même chiffre dans une combinaison (ce qui exclue des combinaisons comme 1223, 1111 etc...). Si toi au contraire tu les veux, il suffit de commenter cette ligne, et du coup tu peux te passer du vecteur marked :
#include <vector>
#include <iostream>

#define TAILLE_ALPHABET 4

char int_to_char(short x){
    if      (x == 0) return 'A';
    else if (x == 1) return 'T';
    else if (x == 2) return 'G';
    else if (x == 3) return 'C';
    return '?';
}

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<TAILLE_ALPHABET;++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);
            f(prof+1,prof_max,perm_suivant,compteur);
        }
    }else{ // le nombre a la taille voulue
        for(unsigned i=0;i<perm.size();++i) std::cout << int_to_char(perm[i]);
        std::cout << std::endl;
        ++compteur;
    }
}

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

int main(){
    perm(2);
    return 0;
}
ce qui donne :
AA
AT
AG
AC
TA
TT
TG
TC
GA
GT
GG
GC
CA
CT
CG
CC
compteur = 16


Note : sur CCM les balises de codes sont entre <>, tu as également un bouton prévu pour au-dessus de la boîte dans laquelle tu tapes ton texte

Bonne chance

Répondre à mamiemando

4

Char Snipeur, le 23 oct 2008 à 14:13:44

Je vais peut être dire une connerie, mais il ne serai pas plus simple et plus rapide de faire des boucles ?
Bonne chance pour ton programme de bio ;) Salutation !  avant je croyais, maintenant je suis fixé.Jésu­s Christ
Char Snipeur

Répondre à Char Snipeur

6

mslider, le 23 oct 2008 à 15:05:46

J'avais pensé à faire des boucles au départ avec ce programme qui d'ailleurs n'est pas complet:


void generateNeighbours(int motifwidth, string m, int nn)
{
   int i, j, k, l; string strmotif;
   vector < int > motif;
   vector < int > neigh;
   vector < vector <int> > partial;
  
   for(i = 0; i < m.size(); i++)
   {
       string base = m.substr(i,1);
       motif.push_back(checkBase(base));
   }
  
   original = m;
   nemotifs.push_back(m);
   neighbours.push_back(motif);
  
   neigh = motif;
   if(nn == 1 || nn == 2)
   {
       for(k = motifwidth-1; k >= 0; k--)
       {
           for(j = 0; j <= 3; j++)
           {
               neigh[k] = j;
               if(neigh != motif)
               {
                   neighbours.push_back(neigh);
                   partial.push_back(neigh);
                   for(int g = 0; g < neigh.size(); g++)
                   {
                       strmotif += nucleotideUnhash(neigh[g]);
                   }
                   nemotifs.push_back(strmotif);
                   strmotif.clear();
               }
           }
           neigh = motif;
       }
   }
  
   if(nn == 2)
   {   
       for(i = 0; i < partial.size(); i++)
       {
           neigh = partial[i];
           for(k = motifwidth-1; k >= 0; k--)
           {
               for(j = 0; j <= 3; j++)
               {
                   neigh[k] = j;
                   if(neigh != partial[i])
                   {
                       neighbours.push_back(neigh);
                       for(int g = 0; g < neigh.size(); g++)
                       {
                           strmotif += nucleotideUnhash(neigh[g]);
                       }
                       nemotifs.push_back(strmotif);
                       strmotif.clear();
                   }
               }
           neigh = partial[i];
           }
       }
   }
   checkMotifs();
  
}


mais après avoir vu le programme de mamiemando plus astucieux je me suis arrêté dans mon élan.
en plus il est rapide j'ai fais un test pour une profondeur de 10 soit 4^10 combinaisons, le temps de calcul = 23 secondes !
Qui dit mieux ?

Merci à toi mamiemando pour ton aide précieuse.

Répondre à mslider

7

 mamiemando, le 23 oct 2008 à 20:16:10

De rien :-)

Pour les boucles c'est possible mais pas de manière simple. Là c'est un parcours d'arbre (algo exponentiel) donc c'est plus naturel de l'écrire en récursif. Les boucles sont plus indiquées pour des algorithmes polynomiaux (parcours d'un tableau ou d'une matrice par exemple).

Bonne continuation

Répondre à mamiemando