web-dev-qa-db-fra.com

Trouver tous les sous-ensembles d'un ensemble

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}

29
Rahul Vyas

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.

  • Pour n = 1, l'ensemble des sous-ensembles est {{}, {1}}
  • Pour n> 1, trouvez l'ensemble des sous-ensembles de 1, ..., n-1 et faites-en deux copies. Pour l'un d'eux, ajoutez n à chaque sous-ensemble. Ensuite, prenez l'union des deux copies.

Edit Pour que tout soit clair:

  • L'ensemble des sous-ensembles de {1} est {{}, {1}}
  • Pour {1, 2}, prenez {{}, {1}}, ajoutez 2 à chaque sous-ensemble pour obtenir {{2}, {1, 2}} et prenez l'union avec {{}, {1}} pour obtenir {{}, {1}, {2}, {1, 2}}
  • Répétez jusqu'à atteindre n
103

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!

48
rgamber

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).

24
Ronald Rey

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.

8
sris

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)
   }  
  }  
6
Jaskaran

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
4
user847988

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
3
sbalian

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.

http://codeding.com/?article=12

3
Prabu Arumugam

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) 
} 
2
cayhorstmann

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);
}
2
BB Chung

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;
    }
}
2
kofhearts

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()) );
}
2
sumanth232

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;
}
0
inblueswithu

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;
}
0
sadik h khan

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;
    }


}
0
kofhearts

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);
}
0
Eric Q

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
0
abe312

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.

0
AndreasT