逐个生成大小为n的子集以降低复杂度

To generate a subset of size n one by one to reduce the complexity?

本文关键字:子集 复杂度 小为      更新时间:2023-10-16
void AlgoMMPCbar::subs(const std::vector<unsigned int>& org, const std::vector<unsigned int>& pre, size_t k, size_t n, SubSets& c){
   if (n <= 1) {
    for(size_t i = k; i < org.size(); i++){
        std::vector<unsigned int> v(pre);// instead of printing...
        v.push_back(org.at(i));
        c.push_back(v);
    }
} else {
    size_t n1 = n - 1;
    for(size_t i = k; i != org.size() - n1; i++){   // 
        std::vector<unsigned int> s(pre);
        s.push_back(org.at(i));
        subs(org,s,i+1,n1,c);
    }
}
}
void AlgoMMPCbar::computeSubSets(const std::vector<unsigned int>& org, size_t& n, SubSets& c){
 c.clear(); // clear previous data
std::vector<unsigned int> pre;
pre.reserve(n+1); // for performance
    if (n==0)
      c.push_back(pre);
else
        subs(org,pre,0, n, c); 
}

以上代码用于生成大小为n的子集以供进一步测试/处理。但我从不需要测试所有这些生成的子集(在最坏的情况下,它会检查所有子集)。程序中最耗时的部分是子集的生成。现在我想将上面的功能转换为一个接一个地生成子集(不是一次全部生成,因此,我可以随时停止进一步的子集生成)。

请分享您的专业知识,将上述功能转换为子集。next()这样的函数,以节省计算时间。

表示ind以递增的顺序维护子集中元素的索引,即

ind[0] < ind[1] < ... < ind[n-1]

找到满足

的最小j
j == n-1 || ind[j] + 1 < ind[j+1]

可以通过

转到下一个子集
ind[j]++
ind[0] = 0; ind[1] = 1; ... ind[j-1] = j-1

注意,新的ind数组仍然排序。您可以很容易地从

开始
ind[] = [0, 1, ..., n-1]

将生成所有通过上述过程迭代的子集。如果你使用一些技巧来"维护"上面的j的值,而不是做线性搜索,你可以有一个快速的代码。

您可以让subs函数返回bool。在ifn<=1分支中,您可以运行各自的检查,如果当前子集匹配,则保存它并返回true。在另一个分支中,用if (subs(..)) return true;之类的东西替换subs调用。最后加一个return false。如果你可能需要多个子集,我不知道该怎么做,而且你也不知道合适的子集有多少。

我将创建某种排序状态向量并按字典顺序遍历它。所以如果你有一组M元素,你想要n大小的子集,你会有一个向量n整数对应于所选的索引。然后你做一个算法next_subset(std::vector<bool> &),它得到下一个子集。例如,对于5的大小为3的子集:

1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5

我相信你可以发现模式(增加最后一个位置;如果它在末尾,将其移回并增加最后两个位置,等等等等)。

如果想要更高效一点,可以将迭代器存储在原始容器中,如果容器不是随机访问的,也可以将整数对和迭代器存储在一起。