2010-10-02 6 views
1

Je dois générer toute la permutation d'une chaîne en sélectionnant certains des éléments. Comme si ma chaîne est "abc", la sortie serait {a, b, c, ab, ba, ac, ca, bc, cb, abc, acb, bac, bca, cab, cba}.Algorithme pour générer toutes les permutations en sélectionnant certains ou tous les charaters

Je pensais un algorithme de base dans lequel je génère toutes les combinaisons possibles de "abc" qui sont {a, b, c, ab, ac, bc, abc}, puis les permuter tous.

Y a-t-il donc un algorithme de permutation efficace par lequel je peux générer toutes les permutations possibles avec des tailles variables.

Le code que j'ai écrit pour cela est:

#include <iostream> 
    #include <stdio.h> 
    #include <stdlib.h> 
    #include <map> 
    using namespace std; 

    int permuteCount = 1; 


    int compare (const void * a, const void * b) 
    { 
     return (*(char*)a - *(char*)b); 
    } 

    void permute(char *str, int start, int end) 
    { 
     // cout<<"before sort : "<<str; 

     // cout<<"after sort : "<<str; 
      do 
     { 
       cout<<permuteCount<<")"<<str<<endl; 
       permuteCount++; 
     }while(next_permutation(str+start,str+end)); 
    } 

void generateAllCombinations(char* str) 
{ 
    int  n, k, i, j, c; 
    n = strlen(str); 

    map<string,int> combinationMap; 

for(k =1; k<=n; k++) 
{ 
    char tempStr[20]; 
    int index =0; 
    for (i=0; i<(1<<n); i++) { 
     index =0; 
     for (j=0,c=0; j<32; j++) if (i & (1<<j)) c++; 
     if (c == k) { 

     for (j=0;j<32; j++) 
      if (i & (1<<j)) 
       tempStr[ index++] = str[j];   
     tempStr[index] = '\0'; 
     qsort (tempStr, index, sizeof(char), compare); 
     if(combinationMap.find(tempStr) == combinationMap.end()) 
     { 
     // cout<<"comb : "<<tempStr<<endl; 
     //cout<<"unique comb : \n"; 
      combinationMap[tempStr] = 1; 
      permute(tempStr,0,k); 
     } /* 
     else 
     { 
      cout<<"duplicated comb : "<<tempStr<<endl; 
     }*/ 
     } 
    } 


} 
} 


    int main() { 


      char str[20]; 
      cin>>str; 

      generateAllCombinations(str); 

      cin>>str; 
    } 

je dois utiliser un hachage pour éviter même combinaison, alors s'il vous plaît laissez-moi savoir comment puis-je faire mieux cet algorithme.

Merci, GG

+0

Je n'ai pas lu votre code, mais votre description verbale semble correcte: utilisez [http://en.wikipedia.org/wiki/Power_set] avec permutation. Pour énumérer un * ensemble d'alimentation *, pensez à incrémenter un nombre binaire, où chaque "chiffre" correspond au nombre de fois qu'un élément d'entrée a été sélectionné pour apparaître dans la sortie. Pour les éléments répétés dans l'ensemble d'entrée, certains "chiffres" du nombre "binaire" deviendront ternaires, ou le nombre de répétitions de cet élément. – rwong

+1

Notez que pour une chaîne de longueur 'N' vous aurez' 2^N-1' sous-ensembles distincts non vides dans le pire des cas (si tous les caractères sont différents) et pour chaque sous-ensemble constitué de caractères 'L', vous Je vais avoir des permutations 'L! –

Répondre

2

Je ne pense pas que vous pouvez écrire le programme beaucoup plus rapide que vous avez déjà. Le problème principal est la taille de sortie: il a l'ordre de n!*2^n (nombre de sous-ensembles * nombre moyen de permutations pour un sous-ensemble), qui est déjà > 10^9 pour une chaîne de 10 caractères différents.

Depuis next_permutation STL ajoute la complexité très limitée pour ces petites chaînes, complexité du temps de votre programme est déjà presque O(output size). Mais vous pouvez rendre votre programme un peu plus simple. En particulier, for(k =1; k<=n; k++) boucle semble inutile: vous calculez déjà la taille du sous-ensemble dans la variable c à l'intérieur. Donc, il suffit d'avoir int k = c au lieu de if (c == k). (Vous devez également considérer le cas du sous-ensemble vide: i == 0)

modifier
En fait, il n'y a que 9.864.100 sorties pour n == 10 (non ~ 10^9). Pourtant, mon point reste le même: votre programme ne gaspille déjà que le temps "O (next_permutation)" pour chaque sortie, ce qui est très, très peu.

+0

ainsi je peux faire la taille de sortie longtemps, puisque je l'emploie pour imprimer le numéro de série. Pour int, je peux générer une combinaison jusqu'à n = 32 –

+1

@GG Juste l'impression de 10^9 chaînes différentes devrait prendre du temps près de l'heure (et environ 10 Go d'espace disque). Est-ce ce que tu veux? –

+0

@nikita Je ne vois pas d'autre moyen? Ou je devrais mettre une restriction qui ne me donne pas un nombre supérieur à 9. –

0

voir cette Algorithm to return all combinations of k elements from n

solutions très détaillées à votre problème

+1

Utilisez des commentaires au lieu des réponses pour cela. –

+1

On dirait que c'est une solution à un problème différent _very_ –

+0

J'ai déjà visité le lien, mais mon problème est différent. –

3
#include <algorithm> 
#include <iostream> 
#include <string> 

int main() { 
    using namespace std; 
    string s = "abc"; 
    do { 
    cout << s << '\n'; 
    } while (next_permutation(s.begin(), s.end())); 
    return 0; 
} 

next_permutation utilise une taille constante, mais vous pouvez ajouter une boucle pour faire face à taille variable. Ou tout simplement stocker dans un ensemble pour éliminer les dupes supplémentaires pour vous:

#include <set> 

int main() { 
    using namespace std; 
    string s = "abc"; 
    set<string> results; 
    do { 
    for (int n = 1; n <= s.size(); ++n) { 
     results.insert(s.substr(0, n)); 
    } 
    } while (next_permutation(s.begin(), s.end())); 
    for (set<string>::const_iterator x = results.begin(); x != results.end(); ++x) { 
    cout << *x << '\n'; 
    } 
    return 0; 
} 
+1

Je ne suis pas capable de comprendre comment faire cela, pouvez-vous élaborer un peu? –

+0

Je suppose qu'il y a quelques problèmes ici. permet de dire que pour la chaîne « CAPV » résultats: 1a2ac3acb4acbc5acc6accb7b8ba9bac10bacc11bc12bca13bcac14bcc15bcca16c17ca18cab19ca bc20cac21cacb22cb23cba24cbac25cbc26cbca27cc28cca29ccab30ccb31ccba mais il devrait être 1a2c3b4ac5ca6ab7ba8bc9cb10cc11bc12cb13abc14acb15bac16bca17cab18cba19acc20cac21cc a22abc23acb24bac25bca26cab27cba28bcc29cbc30ccb31abcc32acbc33accb34bacc35bcac36bc ca37cabc38cacb39cbac40cbca41ccab42ccba –

+0

@GG: Ah, je l'ai raté tout d'abord: next_permutation exige l'état initial à trier, si vous voulez passer par tous permutations. Utilisez std :: tri si nécessaire. –

Questions connexes