生成一个集合的所有子集,使它们的集合等于整个集合
Generating all subsets of a set, so that their reunion equals the whole set
我有一个问题,我正试图在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;
}
我认为你最好使用bitset。给定一个包含N个元素的集合S,你可以将S中的每个元素映射到一个位,然后通过包含与'1'对应的元素来生成该子集。
例如给定S = {A, B, C}你得到
000 -> {}
001 -> {C}
010 -> {B}
011 -> {B, C}
100 -> {A}
101 -> {A, C}
110 -> {A, B}
111 -> {A, B, C}
来自"partitions"包的listParts
函数似乎可以工作:
> 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)
>
相关文章:
- 处理多个异常集合的C++方法
- 给定n个元素的m个集合.在C++中找到出现在最大集合数中的元素
- 如何将ampl中的集合表示为c++中的向量
- 显示字符串的集合和子集
- 在尝试使用递归查找集合子集的总数时,我遇到了分割错误
- 打印给定大小的集合的所有子集并计算子集
- 给定一组正整数 <=k 及其 n 个子集,找到哪些子集对给出原始集合的并集
- (也许是NP-Hard)求一个集合的子集总数,使得每个子集在与其所有元素相乘时的值都大于X
- 如何生成集合的所有唯一子集
- 动态规划:计算集合中存在多少个升序子集
- 递归函数,用于使用位掩码 c++ 显示集合的所有子集
- 拘泥于处理(数学)集合和子集的练习
- 生成给定集合的子集(使用递归)的程序的执行涉及哪些步骤
- 用于访问集合c++的排序子集的数据结构
- 一个多索引,其中一个索引是整个集合的子集
- 从一组集合中找到集合子集的最佳方法
- 使用0来显示不存在元素的集合的子集
- 从一个集合生成所有可能的有序子集
- 如何将一个集合分成K个子集,使得子集中元素的和最小
- 生成一个集合的所有子集,使它们的集合等于整个集合