生成集合的所有子集,以便它们的团聚等于整个集合

时间:2015-09-14 08:57:54

标签: c++ r vector rcpp

我有一个问题,我试图在C ++中实现。给定一组数字,我想生成所有子集,以便这些子集的重聚等于整个集合。

例如,A = {1,2,3}我想获得: (1,2,3)
(1,2)(3)
(1,3)(2)
(1)(2,3)
(1)(2)(3) 我获得这些子集的顺序无关紧要。

我试图在C ++ / RCpp中这样做,因为在R中它往往是我所拥有的代码的瓶颈。我目前的想法是建立一个结构 X vector<vector<vector <int> > >我逐个添加所有向量。 循环通过集合A,

  • 表示1,我将{[(1)]}添加到X {1};
  • 我这样添加下一个元素;假设我在X {1} = [(1)(2)]和X {2} = [(1,2)],并且要添加的下一个数字是3.然后我通过X的元素循环如果我遇到只有一个向量的元素(如X {2}),那么我返回[(1,2)(3)]和[(1,2,3)]。如果我遇到一个带有两个向量的元素(如X {1}),那么我循环遍历向量,对于1我返回[(1,3)(2)]而对于2我返回[(1),(2) ,3)],最后我添加[(1)(2),(3)]。

问题是这个实现证明比纯R中的类似实现慢,这已经很慢了。

是否有一种稍微有效的方法来生成这些子集? 也许首先生成所有子集(可以在R中轻松完成),然后按顺序对它们进行分组(但我还没弄清楚如何)。

编辑:C ++代码(相当长)

std::vector<std::vector < int> > push_one(std::vector<int> x, int add) {
  std::vector< std::vector <int> > res;
  res.push_back(x);

  std::vector<int> newvec;
  newvec.push_back(add);

  res.push_back(newvec);

  return res;
}


std::vector<std::vector<std::vector <int> > > push_two(std::vector<int> x, int add) {

  std::vector<std::vector <int> > newvec;
  std::vector< std::vector< std::vector<int> > > res;
  res.push_back(push_one(x, add));

  x.push_back(add);

  newvec.push_back(x);
  res.push_back(newvec);


  return res;
}


// push_one_rest does the same as push_one, just that it takes a 'rest' argument, that adds another (vector of vectors) at the end.
std::vector<std::vector < int> > push_one_rest(std::vector<int> x, int add, std::vector<std::vector<int> > rest) {
  std::vector< std::vector <int> > res;
  res.push_back(x);

  std::vector<int> newvec;
  newvec.push_back(add);

  res.push_back(newvec);
  res.insert(res.end(), rest.begin(), rest.end());
  return res;
}

//push_two_rest does the same as push_two but it takes the rest argument adding at the end of every element.

std::vector<std::vector<std::vector <int> > > push_two_rest(std::vector<int> x, int add, std::vector<std::vector<int> > rest) {

  std::vector<std::vector <int> > newvec;
  std::vector< std::vector< std::vector<int> > > res;


  //res.push_back(push_one_rest(x, add, rest));



  x.push_back(add);

  newvec.push_back(x);
  newvec.insert(newvec.end(), rest.begin(), rest.end());

  res.push_back(newvec);


  return res;
}


// additref adds a new number.

void additref(std::vector<std::vector<std::vector<int> > > &x, int add) {
  int xsize = x.size();
  for(int i = 0; i<xsize; i++) {
    std::vector<std::vector<int> > herevec = x[i];

    if(herevec.size()==1) {
      std::vector<int> actualvec = herevec[0];
      std::vector<std::vector<std::vector <int> > > newvec = push_two(actualvec, add);
      x.insert(x.end(), newvec.begin(), newvec.end() );
    }

    if(herevec.size()>1) {

      std::vector<int> addvec;
      addvec.push_back(add);

      for(int i=0; i<herevec.size(); i++) {

        // put the rest into rest
        std::vector<int> basis = herevec[i];

        std::vector<std::vector<int> > rest = herevec;  

        rest.erase (rest.begin()+i);


        std::vector<std::vector<std::vector <int> > > newvec2 = push_two_rest(basis, add, rest);


        x.insert(x.end(),newvec2.begin(), newvec2.end() );
      }
      herevec.push_back(addvec);
      x.push_back(herevec);
    }
  }
  x.erase (x.begin(),x.begin()+xsize);

}


// The function which adds the numbers one after another.

std::vector<std::vector<std::vector <int> > > divide(std::vector<int> division) {
  std::vector<std::vector<std::vector <int> > > res;

  std::vector<int> x;
  x.push_back(division[0]);
  std::vector<std::vector<int> > x2;
  x2.push_back(x);

  res.push_back(x2);


  for(std::vector<int>::iterator it4 = division.begin()+1; it4<division.end(); it4++) {
    additref(res, *it4);
  }
  return res;
}

2 个答案:

答案 0 :(得分:0)

我认为你最好使用bitset。给定N个元素的集合S,您可以将S的每个元素映射到一个位,然后通过包含对应于'1'的elemnst来生成子集。

如果给出S = {A,B,C},则得到

000 -> {}
001 -> {C}
010 -> {B}
011 -> {B, C}
100 -> {A}
101 -> {A, C}
110 -> {A, B}
111 -> {A, B, C}

答案 1 :(得分:0)

来自&#34;分区的listParts功能&#34;包似乎有效:

> require(partitions)

> listParts(4)
[[1]]
[1] (1,2,3,4)

[[2]]
[1] (1,2,4)(3)

[[3]]
[1] (1,2,3)(4)

[[4]]
[1] (1,3,4)(2)

[[5]]
[1] (2,3,4)(1)

[[6]]
[1] (1,4)(2,3)

[[7]]
[1] (1,2)(3,4)

[[8]]
[1] (1,3)(2,4)

[[9]]
[1] (1,4)(2)(3)

[[10]]
[1] (1,2)(3)(4)

[[11]]
[1] (1,3)(2)(4)

[[12]]
[1] (2,4)(1)(3)

[[13]]
[1] (2,3)(1)(4)

[[14]]
[1] (3,4)(1)(2)

[[15]]
[1] (1)(2)(3)(4)

>