我有一个问题,我试图在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,
问题是这个实现证明比纯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;
}
答案 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)
>