Permutations avec répétitions en C++
Résolu/Fermé
mslider
Messages postés
109
Date d'inscription
jeudi 21 octobre 2004
Statut
Membre
Dernière intervention
7 mars 2010
-
21 oct. 2008 à 20:52
mamiemando Messages postés 33459 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 8 janvier 2025 - 23 oct. 2008 à 20:16
mamiemando Messages postés 33459 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 8 janvier 2025 - 23 oct. 2008 à 20:16
6 réponses
mslider
Messages postés
109
Date d'inscription
jeudi 21 octobre 2004
Statut
Membre
Dernière intervention
7 mars 2010
22 oct. 2008 à 12:54
22 oct. 2008 à 12:54
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.
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.
mslider
Messages postés
109
Date d'inscription
jeudi 21 octobre 2004
Statut
Membre
Dernière intervention
7 mars 2010
22 oct. 2008 à 21:41
22 oct. 2008 à 21:41
[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 !
#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 !
mamiemando
Messages postés
33459
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
8 janvier 2025
7 813
23 oct. 2008 à 12:46
23 oct. 2008 à 12:46
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 :
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 :
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
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
Char Snipeur
Messages postés
9813
Date d'inscription
vendredi 23 avril 2004
Statut
Contributeur
Dernière intervention
3 octobre 2023
1 298
23 oct. 2008 à 14:13
23 oct. 2008 à 14:13
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 ;)
Bonne chance pour ton programme de bio ;)
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
mslider
Messages postés
109
Date d'inscription
jeudi 21 octobre 2004
Statut
Membre
Dernière intervention
7 mars 2010
23 oct. 2008 à 15:05
23 oct. 2008 à 15:05
j'avais pensé à faire des boucles au départ avec ce programme qui d'ailleurs n'est pas complet:
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.
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.
mamiemando
Messages postés
33459
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
8 janvier 2025
7 813
23 oct. 2008 à 20:16
23 oct. 2008 à 20:16
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
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