En utilisant la récursivité et les retours en arrière pour générer toutes les combinaisons possibles
Je suis en train de mettre en œuvre une classe qui permettra de générer de tous les possibles non ordonnée de n-tuples ou les combinaisons d'un certain nombre d'éléments et la taille de la combinaison.
En d'autres termes, lors de l'appel de cette:
NTupleUnordered unordered_tuple_generator(3, 5, print);
unordered_tuple_generator.Start();
print() étant une fonction de rappel définie dans le constructeur.
La sortie doit être:
{0,1,2}
{0,1,3}
{0,1,4}
{0,2,3}
{0,2,4}
{0,3,4}
{1,2,3}
{1,2,4}
{1,3,4}
{2,3,4}
C'est ce que j'ai à ce jour:
class NTupleUnordered {
public:
NTupleUnordered( int k, int n, void (*cb)(std::vector<int> const&) );
void Start();
private:
int tuple_size; //how many
int set_size; //out of how many
void (*callback)(std::vector<int> const&); //who to call when next tuple is ready
std::vector<int> tuple; //tuple is constructed here
void add_element(int pos); //recursively calls self
};
et c'est la mise en œuvre de la fonction récursive, Start() est juste un coup de pouce de la fonction d'avoir une interface épurée, elle n'appelle add_element(0);
void NTupleUnordered::add_element( int pos )
{
//base case
if(pos == tuple_size)
{
callback(tuple); //prints the current combination
tuple.pop_back(); //not really sure about this line
return;
}
for (int i = pos; i < set_size; ++i)
{
//if the item was not found in the current combination
if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
{
//add element to the current combination
tuple.push_back(i);
add_element(pos+1); //next call will loop from pos+1 to set_size and so on
}
}
}
Si je voulais générer toutes les combinaisons possibles d'une taille constante N, permet de dire que les combinaisons de taille 3 que je pouvais faire:
for (int i1 = 0; i1 < 5; ++i1)
{
for (int i2 = i1+1; i2 < 5; ++i2)
{
for (int i3 = i2+1; i3 < 5; ++i3)
{
std::cout << "{" << i1 << "," << i2 << "," << i3 << "}\n";
}
}
}
Si N n'est pas une constante, vous avez besoin d'une fonction récursive, qui imite le ci-dessus
la fonction par l'exécution de chaque boucle for dans son propre cadre. Lorsque, pour la boucle se termine,
programme renvoie à l'image précédente, en d'autres termes, les retours en arrière.
J'ai toujours eu des problèmes avec la récursivité, et maintenant j'ai besoin de le combiner avec des retours en arrière pour générer toutes les combinaisons possibles. Tous les pointeurs de ce que je fais mal? Ce que je devrais faire ou je suis dominant?
P. S: C'est un collège d'affectation, qui comprend également essentiellement faire la même chose à l'ordre n-tuples.
Merci d'avance!
/////////////////////////////////////////////////////////////////////////////////////////
Voulais juste faire un suivi avec le bon code, juste au cas où quelqu'un d'autre se pose la question de la même chose.
void NTupleUnordered::add_element( int pos)
{
if(static_cast<int>(tuple.size()) == tuple_size)
{
callback(tuple);
return;
}
for (int i = pos; i < set_size; ++i)
{
//add element to the current combination
tuple.push_back(i);
add_element(i+1);
tuple.pop_back();
}
}
Et pour le cas de l'ordre de n-tuples:
void NTupleOrdered::add_element( int pos )
{
if(static_cast<int>(tuple.size()) == tuple_size)
{
callback(tuple);
return;
}
for (int i = pos; i < set_size; ++i)
{
//if the item was not found in the current combination
if( std::find(tuple.begin(), tuple.end(), i) == tuple.end())
{
//add element to the current combination
tuple.push_back(i);
add_element(pos);
tuple.pop_back();
}
}
}
Merci Jason pour vos approfondie de la réponse!
L'affectation exige que je les stocker, mais peut-être que ça va m'aider à mieux le comprendre. Merci pour les conseils, je vais essayer.
Une autre chose,
pos
est juste la taille de votre tuple
vecteur, de sorte que vous devriez être en utilisant tuple.size()
à la place.vous avez raison sur l'utilisation de
tuple.size()
, merci pour cette remarqueOriginalL'auteur Lechuzza | 2012-03-04
Vous devez vous connecter pour publier un commentaire.
Une bonne façon de penser à la formation N combinaisons est de considérer la structure comme un arbre de combinaisons. Parcourant l'arbre devient alors naturel de penser au sujet de la nature récursive de l'algorithme que vous souhaitez mettre en œuvre, et comment le processus récursif serait de travailler.
Disons, par exemple, que nous avons la séquence,
{1, 2, 3, 4}
, et nous souhaitons trouver tous les 3-combinaisons dans ce jeu. "L'arbre" de combinaisons seraient alors l'aspect suivant:De la traversée de la racine à l'aide d'un pré-ordre transversal, et d'identifier une combinaison lorsque nous arrivons à un nœud feuille, nous obtenons les combinaisons:
Donc en gros, l'idée serait de séquence par le biais d'un tableau à l'aide de la valeur de l'indice, que pour chaque étape de la récursion (qui serait dans ce cas les "niveaux" de l'arbre), les augmentations dans le tableau pour obtenir la valeur qui serait inclus dans la combinaison. Notez également que nous avons seulement besoin de répéter N fois. Par conséquent, vous n'avez pas quelqu'fonction récursive dont la signature qui ressemblerait à quelque chose comme ce qui suit:
où la
step_val
indique dans quelle mesure nous sommes répéter, learray_index
valeur nous indique où nous en sommes dans le jeu pour commencer à ajouter des valeurs à latuple
, et latuple
, une fois que nous aurons terminé, sera une instance d'une combinaison de l'ensemble.Vous devez l'appeler
recursive_comb
à partir d'un autre non-fonction récursive qui, en gros, "commence" le processus récursif par l'initialisation de latuple
vecteur et de saisir le maximum d'étapes récursives (c'est à dire, le nombre de valeurs que nous voulons dans le tuple):Enfin votre
recusive_comb
fonction serait quelque chose comme:Vous pouvez voir un exemple de ce code ici: http://ideone.com/78jkV
Noter que ce n'est pas le plus rapide version de l'algorithme, que nous sommes en train supplémentaire branches nous n'avons pas besoin de prendre qui créer certains inutile de copie et d'appels de fonction, etc. ... mais j'espère qu'il obtient dans l'idée générale de la récursivité et de retours en arrière, et comment les deux fonctionnent ensemble.
OriginalL'auteur Jason
Personnellement, je aller avec une simple solution itérative.
Vous représenter ensemble de nœuds comme un ensemble de bits. Si vous avez besoin de 5 nœuds alors 5 bits, chaque bit représentant un nœud spécifique. Si vous voulez que 3 de ces dans votre tupple ensuite, vous avez juste besoin de mettre 3 des bits et le suivi de leur emplacement.
Fondamentalement, c'est une simple variation sur le fonding de tous les différents sous-ensembles de nœuds de combinaisons. Où le classique de la mise en œuvre est de représenter l'ensemble de nœuds comme un entier. Chacun des bits de l'entier représente un nœud. L'ensemble vide est 0. Ensuite, vous avez juste incrémenter le nombre entier chaque nouvelle valeur est un nouvel ensemble de nœuds (la séquence de bits représentant l'ensemble des nœuds). Juste dans cette variante, vous assurez-vous qu'il y a toujours 3 nœuds.
Juste pour m'aider à penser, je commence avec les 3 premiers nœuds active { 4, 3, 2 }. Puis-je compter vers le bas. Mais il serait trivial de modifier ce nombre dans l'autre sens.
Principal est trivial:
De sortie est:
Une version de shiftBits() à l'aide d'une boucle
Astari : +1 pour une solution intéressante. BTW, petite question ... vous avez mentionné cette méthode est itérative, mais il semble que
shiftBits
est appelée récursivement, donc au final c'est toujours un algorithme récursif, droit?Son récursive de la même façon, l'addition est récursive. 9999 + 1. => 9+1 = 0 avec un plus, donc maintenant, je dois ajouter (en dizaines) 1 + 9 = 0 avec un plus, donc maintenant je ajouter (en centaines) 1 + 9 = 0 avec un plus, donc maintenant je ajouter (en milliers) 1 + 9 = 0 avec un plus, donc maintenant, j'ai (à 10 KM) 1. Il peut utiliser la récursivité en interne pour mettre en œuvre une opération de déplacement, mais
I would not call it a recursive solution
car il n'est pas recursing à travers le jeu de résultats. Comme dans le plus exemple, ici, je suis recusing à travers les 4 chiffres pas à travers l'ensemble de résultats de plus de 10 000 éléments (donc je ne dirais pas plus récursif).OriginalL'auteur Martin York
Dans MATLAB:
OriginalL'auteur Wisentgenus