J'ai besoin d'un algorithme pour trouver tous les sous-ensembles d'un ensemble où le nombre d'éléments d'un ensemble est n
.
S={1,2,3,4...n}
Edit: J'ai du mal à comprendre les réponses fournies jusqu'à présent. Je voudrais avoir des exemples étape par étape de la façon dont les réponses fonctionnent pour trouver les sous-ensembles.
Par exemple,
S={1,2,3,4,5}
Comment savez-vous que {1}
et {1,2}
sont des sous-ensembles?
Quelqu'un peut-il m'aider avec une fonction simple en c ++ à trouver des sous-ensembles de {1,2,3,4,5}
C'est très simple de faire cela récursivement. L'idée de base est que pour chaque élément, l'ensemble de sous-ensembles peut être divisé également entre ceux qui contiennent cet élément et ceux qui n'en contiennent pas, et ces deux ensembles sont égaux par ailleurs.
Edit Pour que tout soit clair:
Il est trop tard pour répondre, mais une approche itérative semble facile ici:
1) pour un ensemble d'éléments n
, obtenez la valeur de 2^n
. Il y aura 2 ^ nn nombre de sous-ensembles. (2 ^ n parce que chaque élément peut être présent (1) ou absent (0). Donc, pour n éléments, il y aura 2 ^ n sous-ensembles.). Par exemple:
for 3 elements, say {a,b,c}, there will be 2^3=8 subsets
2) Obtenez une représentation binaire de 2^n
. Par exemple:
8 in binary is 1000
3) Passez de 0
à (2^n - 1)
. Dans chaque itération, pour chaque 1 dans la représentation binaire, formez un sous-ensemble avec des éléments correspondant à l'index de ce 1 dans la représentation binaire .
For the elements {a, b, c}
000 will give {}
001 will give {c}
010 will give {b}
011 will give {b, c}
100 will give {a}
101 will give {a, c}
110 will give {a, b}
111 will give {a, b, c}
4) Faites une union de tous les sous-ensembles ainsi trouvés à l'étape 3. Retournez. Par exemple:
Simple union of above sets!
Au cas où quelqu'un d'autre viendrait se poser la question, voici une fonction utilisant l'explication de Michael en C++
vector< vector<int> > getAllSubsets(vector<int> set)
{
vector< vector<int> > subset;
vector<int> empty;
subset.Push_back( empty );
for (int i = 0; i < set.size(); i++)
{
vector< vector<int> > subsetTemp = subset;
for (int j = 0; j < subsetTemp.size(); j++)
subsetTemp[j].Push_back( set[i] );
for (int j = 0; j < subsetTemp.size(); j++)
subset.Push_back( subsetTemp[j] );
}
return subset;
}
Sachez cependant que cela retournera un ensemble de taille 2 ^ N avec TOUS les sous-ensembles possibles, ce qui signifie qu’il y aura éventuellement des doublons. Si vous ne le souhaitez pas, je suggérerais d'utiliser réellement une set
au lieu d'une vector
(que j'avais l'habitude d'utiliser pour éviter les itérateurs dans le code).
Si vous voulez énumérer tous les sous-ensembles possibles, regardez this paper. Ils discutent de différentes approches telles que l'ordre lexicographique, le codage gris et la séquence du banquier. Ils donnent un exemple de mise en œuvre de la séquence du banquier et discutent de différentes caractéristiques des solutions, par ex. performance.
Ici, je l’ai expliqué en détail . Faites un vote positif si vous aimez le post de blog.
http://cod3rutopia.blogspot.in/
De toute façon, si vous ne trouvez pas mon blog, voici l'explication.
C'est un problème de nature récursive.
Pour qu'un élément soit présent dans un sous-ensemble, il existe 2 options:
1) Il est présent dans le set
2) Il est absent dans le set.
C'est la raison pour laquelle un ensemble de n nombres a 2 ^ n sous-ensembles (2 options par élément).
Voici le pseudo-code (C++) pour imprimer tous les sous-ensembles, suivi d'un exemple expliquant le fonctionnement du code . 1) Un [] est le tableau de nombres dont vous voulez connaître les sous-ensembles. bool a [] est le tableau de booléens où un [i] indique si le nombre A [i] est présent ou non dans l'ensemble.
print(int A[],int low,int high)
{
if(low>high)
{
for(all entries i in bool a[] which are true)
print(A[i])
}
else
{set a[low] to true //include the element in the subset
print(A,low+1,high)
set a[low] to false//not including the element in the subset
print(A,low+1,high)
}
}
Voici un algorithme récursif simple en python pour trouver tous les sous-ensembles d'un ensemble:
def find_subsets(so_far, rest):
print 'parameters', so_far, rest
if not rest:
print so_far
else:
find_subsets(so_far + [rest[0]], rest[1:])
find_subsets(so_far, rest[1:])
find_subsets([], [1,2,3])
La sortie sera la suivante: $ Python subsets.py
parameters [] [1, 2, 3]
parameters [1] [2, 3]
parameters [1, 2] [3]
parameters [1, 2, 3] []
[1, 2, 3]
parameters [1, 2] []
[1, 2]
parameters [1] [3]
parameters [1, 3] []
[1, 3]
parameters [1] []
[1]
parameters [] [2, 3]
parameters [2] [3]
parameters [2, 3] []
[2, 3]
parameters [2] []
[2]
parameters [] [3]
parameters [3] []
[3]
parameters [] []
[]
Regardez la vidéo suivante de Stanford pour une explication de Nice de cet algorithme:
https://www.youtube.com/watch?v=NdF1QDTRkck&feature=PlayList&p=FE6E58F856038C69&index=9
Voici une implémentation de la solution de Michael pour tout type d'élément dans std :: vector.
#include <iostream>
#include <vector>
using std::vector;
using std::cout;
using std::endl;
// Find all subsets
template<typename element>
vector< vector<element> > subsets(const vector<element>& set)
{
// Output
vector< vector<element> > ss;
// If empty set, return set containing empty set
if (set.empty()) {
ss.Push_back(set);
return ss;
}
// If only one element, return itself and empty set
if (set.size() == 1) {
vector<element> empty;
ss.Push_back(empty);
ss.Push_back(set);
return ss;
}
// Otherwise, get all but last element
vector<element> allbutlast;
for (unsigned int i=0;i<(set.size()-1);i++) {
allbutlast.Push_back( set[i] );
}
// Get subsets of set formed by excluding the last element of the input set
vector< vector<element> > ssallbutlast = subsets(allbutlast);
// First add these sets to the output
for (unsigned int i=0;i<ssallbutlast.size();i++) {
ss.Push_back(ssallbutlast[i]);
}
// Now add to each set in ssallbutlast the last element of the input
for (unsigned int i=0;i<ssallbutlast.size();i++) {
ssallbutlast[i].Push_back( set[set.size()-1] );
}
// Add these new sets to the output
for (unsigned int i=0;i<ssallbutlast.size();i++) {
ss.Push_back(ssallbutlast[i]);
}
return ss;
}
// Test
int main()
{
vector<char> a;
a.Push_back('a');
a.Push_back('b');
a.Push_back('c');
vector< vector<char> > sa = subsets(a);
for (unsigned int i=0;i<sa.size();i++) {
for (unsigned int j=0;j<sa[i].size();j++) {
cout << sa[i][j];
}
cout << endl;
}
return 0;
}
Sortie:
(empty line)
a
b
ab
c
ac
bc
abc
Vous n'avez pas à vous mêler de récursivité et autres algorithmes complexes. Vous pouvez trouver tous les sous-ensembles en utilisant des modèles de bits (décimaux à binaires) de tous les nombres compris entre 0 et 2 ^ (N-1). Ici, N est la cardinalité ou le nombre d'éléments dans cet ensemble. La technique est expliquée ici avec une implémentation et une démonstration.
Voici une solution à Scala:
def subsets[T](s : Set[T]) : Set[Set[T]] =
if (s.size == 0) Set(Set()) else {
val tailSubsets = subsets(s.tail);
tailSubsets ++ tailSubsets.map(_ + s.head)
}
Bottom up avec O(n) solution spatiale
#include <stdio.h>
void print_all_subset(int *A, int len, int *B, int len2, int index)
{
if (index >= len)
{
for (int i = 0; i < len2; ++i)
{
printf("%d ", B[i]);
}
printf("\n");
return;
}
print_all_subset(A, len, B, len2, index+1);
B[len2] = A[index];
print_all_subset(A, len, B, len2+1, index+1);
}
int main()
{
int A[] = {1, 2, 3, 4, 5, 6, 7};
int B[7] = {0};
print_all_subset(A, 7, B, 0, 0);
}
Voici un pseudocode. Vous pouvez couper les mêmes appels récursifs en stockant les valeurs de chaque appel au fur et à mesure et avant de vérifier les appels récursifs si la valeur d'appel est déjà présente.
L'algorithme suivant aura tous les sous-ensembles à l'exclusion de l'ensemble vide.
list * subsets(string s, list * v){
if(s.length() == 1){
list.add(s);
return v;
}
else
{
list * temp = subsets(s[1 to length-1], v);
int length = temp->size();
for(int i=0;i<length;i++){
temp.add(s[0]+temp[i]);
}
list.add(s[0]);
return temp;
}
}
Voici un code de travail que j'ai écrit il y a quelque temps
// Return all subsets of a given set
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<string>
#include<sstream>
#include<cstring>
#include<climits>
#include<cmath>
#include<iterator>
#include<set>
#include<map>
#include<stack>
#include<queue>
using namespace std;
typedef vector<int> vi;
typedef vector<long long> vll;
typedef vector< vector<int> > vvi;
typedef vector<string> vs;
vvi get_subsets(vi v, int size)
{
if(size==0) return vvi(1);
vvi subsets = get_subsets(v,size-1);
vvi more_subsets(subsets);
for(typeof(more_subsets.begin()) it = more_subsets.begin(); it !=more_subsets.end(); it++)
{
(*it).Push_back(v[size-1]);
}
subsets.insert(subsets.end(), (more_subsets).begin(), (more_subsets).end());
return subsets;
}
int main()
{
int ar[] = {1,2,3};
vi v(ar , ar+int(sizeof(ar)/sizeof(ar[0])));
vvi subsets = get_subsets(v,int((v).size()));
for(typeof(subsets.begin()) it = subsets.begin(); it !=subsets.end(); it++)
{
printf("{ ");
for(typeof((*it).begin()) it2 = (*it).begin(); it2 !=(*it).end(); it2++)
{
printf("%d,",*it2 );
}
printf(" }\n");
}
printf("Total subsets = %d\n",int((subsets).size()) );
}
Pour ceux qui veulent une implémentation simple utilisant std :: vector et std :: set pour l'algorithme de Michael Borgwardt:
// Returns the subsets of given set
vector<set<int> > subsets(set<int> s) {
vector<set<int> > s1, s2;
set<int> empty;
s1.Push_back(empty); // insert empty set
// iterate over each element in the given set
for(set<int>::iterator it=s.begin(); it!=s.end(); ++it) {
s2.clear(); // clear all sets in s2
// create subsets with element (*it)
for(vector<set<int> >::iterator s1iter=s1.begin(); s1iter!=s1.end(); ++s1iter) {
set<int> temp = *s1iter;
temp.insert(temp.end(), *it);
s2.Push_back(temp);
}
// update s1 with new sets including current *it element
s1.insert(s1.end(), s2.begin(), s2.end());
}
// return
return s1;
}
un simple bitmasking peut faire l'affaire, comme indiqué plus haut ....
#include<iostream>
#include<cstdio>
#define pf printf
#define sf scanf
using namespace std;
void solve(){
int t; char arr[99];
cin >> t;
int n = t;
while( t-- )
{
for(int l=0; l<n; l++) cin >> arr[l];
for(int i=0; i<(1<<n); i++)
{
for(int j=0; j<n; j++)
if(i & (1 << j))
pf("%c", arr[j]);
pf("\n");
}
}
}
int main() {
solve();
return 0;
}
voici ma solution récursive.
vector<vector<int> > getSubsets(vector<int> a){
//base case
//if there is just one item then its subsets are that item and empty item
//for example all subsets of {1} are {1}, {}
if(a.size() == 1){
vector<vector<int> > temp;
temp.Push_back(a);
vector<int> b;
temp.Push_back(b);
return temp;
}
else
{
//here is what i am doing
// getSubsets({1, 2, 3})
//without = getSubsets({1, 2})
//without = {1}, {2}, {}, {1, 2}
//with = {1, 3}, {2, 3}, {3}, {1, 2, 3}
//total = {{1}, {2}, {}, {1, 2}, {1, 3}, {2, 3}, {3}, {1, 2, 3}}
//return total
int last = a[a.size() - 1];
a.pop_back();
vector<vector<int> > without = getSubsets(a);
vector<vector<int> > with = without;
for(int i=0;i<without.size();i++){
with[i].Push_back(last);
}
vector<vector<int> > total;
for(int j=0;j<without.size();j++){
total.Push_back(without[j]);
}
for(int k=0;k<with.size();k++){
total.Push_back(with[k]);
}
return total;
}
}
Une solution récursive élégante qui correspond à la meilleure explication de réponse ci-dessus. L’opération vectorielle principale n’est que de 4 lignes. crédit au livre "Guide to Competitive Programming" de Laaksonen, Antti.
// #include <iostream>
#include <vector>
using namespace std;
vector<int> subset;
void search(int k, int n) {
if (k == n+1) {
// process subset - put any of your own application logic
// for (auto i : subset) cout<< i << " ";
// cout << endl;
}
else {
// include k in the subset
subset.Push_back(k);
search(k+1, n);
subset.pop_back();
// don't include k in the subset
search(k+1,n);
}
}
int main() {
// find all subset between [1,3]
search(1, 3);
}
Cette question est ancienne. Mais il existe une solution récursive simple et élégante au problème de OP.
using namespace std;
void recsub(string sofar, string rest){
if(rest=="") cout<<sofar<<endl;
else{
recsub(sofar+rest[0], rest.substr(1)); //including first letter
recsub(sofar, rest.substr(1)); //recursion without including first letter.
}
}
void listsub(string str){
recsub("",str);
}
int main(){
listsub("abc");
return 0;
}
//output
abc
ab
ac
a
bc
b
c
//end: there's a blank output too representing empty subset
un moyen simple serait le pseudo code suivant:
Set getSubsets(Set theSet)
{
SetOfSets resultSet = theSet, tempSet;
for (int iteration=1; iteration < theSet.length(); iteration++)
foreach element in resultSet
{
foreach other in resultSet
if (element != other && !isSubset(element, other) && other.length() >= iteration)
tempSet.append(union(element, other));
}
union(tempSet, resultSet)
tempSet.clear()
}
}
Eh bien, je ne suis pas tout à fait sûr que c'est correct, mais ça a l'air d'aller.