我试图编写一个算法来查找数组中项目的所有k
长度组合,但这也必须在索引n
之前使用j
个项目,因为我们希望的这些(n,j)
对中有很多对。
使用索引2之前的至少一个项目(又名{1,2,3,4}
)从restrictions = {{1,2}}
查找所有两个项目组合。这应该导致{{1,2},{1,3},{1,4},{2,3},{2,4}}
。
使用索引2前的至少一个项目和{4}之前的两个项目{1,2,3,4,5,6,7}
查找restrictions = {{1,2},{2,4}}
中的所有三个项目组合。
我已经能够找到从一堆中选择一个项目的所有组合。
void add_combinations_to(vector<int> prefix, vector<vector<int>>::iterator start,
vector<vector<int>>::iterator stop, vector<vector<int>>& ret) {
if(start == stop) {ret.push_back(prefix); return;}
for(auto v : *start) {
auto next = prefix;
next.push_back(v);
add_combinations_to(next, start + 1, stop, ret);
}
};
int main() {
vector<vector<int>> v{{1,2},{3,4}};
vector<vector<int>> ret;
vector<int> init{};
add_combinations_to(init, v.begin(), v.end(), ret);
// ret now contains {{1,3},{1,4},{2,3},{2,4}}
}
我觉得有一种方法可以扩展它。现在我需要退一步,但建议会很棒。在大多数情况下,这只是一个
答案 0 :(得分:2)
与许多序列枚举问题一样,这个问题产生了标准的词典枚举算法(引自Algorithm for "consolidating" N items into K):
如果没有其他限制,则j
序列p == p0, p1, …, pj−1
的长度可以是长度的前缀 - k
{if} n
事件的k−j < n−pj−1
组合pj−1 < n − k + j)
}。我们可以将其重写为/* Finds the (lexicographically) next prefix of a k-combination from n
* values, and returns the length of that prefix.
* If there is no possible next prefix, returns 0.
* Note: k is implicit in the length of the combination
*/
size_t nextPrefix(std::vector<size_t>& comb, size_t n) {
size_t k = comb.size();
for (size_t j = k; j;) {
--j;
if (comb[j] < n - k + j) {
++comb[j];
return j + 1;
}
}
return 0;
}
。
因此,对于不受限制的k,n组合,以下简单函数将完成上述通用算法的步骤a和b:
ki
为了继续解决实际问题,我们注意到表单的任何限制都包含ni
个ki
值的ni
&#34;最终将完全相同的测试,因为该限制可以改为&#34; n
- 长度前缀是<k, n>
值的组合。&#34;
因此,我们可以使用对向量替换上述函数中的size_t nextPrefix(std::vector<size_t>& comb,
std::vector<std::pair<size_t, size_t>> const& restrictions) {
for (size_t j = comb.size(); j;) {
--j;
/* Test all applicable conditions */
if (std::all_of(restrictions.begin(), restrictions.end(),
[&j, &comb](std::pair<size_t, size_t> const& rest) {
return j >= rest.first
or comb[j] < rest.second - rest.first + j;})) {
++comb[j];
return j + 1;
}
}
return 0;
}
参数(其中最后一对精确为void firstSuffix(std::vector<size_t>& comb, size_t pfx_length) {
size_t val = pfx_length ? comb[pfx_length - 1] + 1 : 0;
for (auto it = comb.begin() + pfx_length; it != comb.end(); ++it)
*it = val++;
}
):
int main() {
std::vector<std::pair<size_t, size_t>> restrictions = {{1, 2}, {2, 4}, {3, 7}};
size_t k = std::max_element(restrictions.begin(), restrictions.end())->first;
if (k == 0) return 0; /* Empty set */
std::vector<size_t> comb(k);
std::size_t pfx = 0;
do {
firstSuffix(comb, pfx);
for (auto const& val : comb) std::cout << std::setw(3) << val;
std::cout << '\n';
} while (pfx = nextPrefix(comb, restrictions));
return 0;
}
(这显然不是最优的。我们可以只计算一个最大值的简单向量,然后根据该最大值测试该元素,而不是检查每个元素的所有限制。)
要实际生成序列,我们需要能够填写后缀(通用算法的最后一步)并构造循环:
(global-set-key [(control tab)] 'indent-rigidly)
然后我们可以编写循环:
(global-set-key (kbd "C-<tab>") 'indent-rigidly)