C++ 如何避免c++;?
我需要编程所有可能的数字集,从C++ 如何避免c++;?,c++,for-loop,C++,For Loop,我需要编程所有可能的数字集,从1到N,用于无排列的任意整数m 因为我不知道如何更好地解释,这里有一些例子: 对于m=2 vector<vector<int>> box; int N = 5; for(int i = 1; i <= N; i++) { for(int j = N; j >= i; j--) { vector<int> dummy; dummy.push_back(i);
1
到N
,用于无排列的任意整数m
因为我不知道如何更好地解释,这里有一些例子:
对于m=2
vector<vector<int>> box;
int N = 5;
for(int i = 1; i <= N; i++) {
for(int j = N; j >= i; j--) {
vector<int> dummy;
dummy.push_back(i);
dummy.push_back(j);
box.push_back(dummy);
}
}
这工作非常好,结果就是我所需要的。但正如前面提到的,m
可以是任意的,我不想费心为m=37
或其他任何东西实现它N
和m
是已知值,但在程序运行时会发生变化。必须有比m=37
案例更好的实现方法来实现37行for循环。有人能帮我吗?我有点不知所措:\
编辑:为了更好地解释我在寻找什么,这里还有一些例子
假设N=5
和m=4
,那么1223
对我来说是一个可行的解决方案,124
不是,因为它很短。假设我已经找到了1223
作为解决方案,那么我就不需要2123
、2213
或这个数字的任何其他排列
编辑2:或者如果你喜欢一个更直观(数学?)的问题公式,那就来吧
考虑
m
维度。使用m
2,您将得到N
大小矩阵。我正在寻找这个矩阵的上(或下)三角形,包括对角线。让我们移动到m=3
,矩阵变成一个三维立方体(或者张量,如果你愿意的话),现在我在寻找上(或者下)四面体,包括对角线平面。对于大于3的维度,我正在寻找超立方体的超四面体,包括超对角线平面。可以使用递归查找所有子集。这可能在风格上有所改进,但下面是一个快速解决问题的方法:
std::vector<std::set<int>> subsets(std::vector<int> x)
{
if (x.size() == 0)
return { std::set<int>() };
else
{
int last = x.back();
x.pop_back();
auto sets = subsets(x);
size_t n = sets.size();
for (size_t i = 0; i < n; i++)
{
std::set<int> s = sets[i];
s.insert(last);
sets.push_back(std::move(s));
}
return sets;
}
}
std::vector子集(std::vector x)
{
如果(x.size()==0)
返回{std::set()};
其他的
{
int last=x.back();
x、 向后弹出();
自动设置=子集(x);
size_t n=sets.size();
对于(大小i=0;i
这将使每个递归步骤的答案数量增加一倍:子集的数量为2^n,正如预期的那样
如果愿意,可以用std::set
替换std::vector
。
以下通用算法允许客户每次访问长度为N,r项序列的每个组合或置换
用法示例:
std::vector<std::vector<int>> box;
std::vector<int> v(N);
std::iota(begin(v), end(v), 1);
for_each_combination(begin(v), begin(v) + M, end(v), [](auto b, auto e) {
box.emplace_back(b, e);
return false;
});
维基百科很好地说明了这一点:它获取数字[0,N+M-1]的所有组合(不重复),然后查找结果中的“间隙”。间隙表示从一个元素的重复到下一个元素的重复的过渡
你传递给这个算法的函子是一个包含索引的范围,该索引进入一个包含你正在组合的元素的集合。例如,如果你想从{x,y}集合中得到三个元素的所有集合,结果是{x,x,x},{x,x,y},{x,y,y},{y,y,y},这个算法通过将索引范围返回到(有序)集合{x,y}:{{0,0,0},{0,0,1},{0,1,1},{1,1,1}来表示这一点
因此,通常要使用它,你有一个向量或包含元素的东西,并使用该算法生成的范围作为该容器的索引。然而,在你的情况下,由于元素只是从1到N的数字,你可以通过向每个索引添加一个来直接使用索引:
for_each_combination_with_repetition(N, M, [&](auto b, auto e) {
for(; b != e; ++b) {
int index = *b;
std::cout << index + 1 << " ";
}
std::cout << '\n';
});
对于每个重复的组合(N,M,[&](自动b,自动e){
对于(;b!=e;++b){
int指数=*b;
std::不久前是否也有同样的问题,也许我会发现……这更适合于“无置换”的可能重复,你的意思是相同集合的不同置换被视为不同集合吗?在这种情况下,更好的术语可能是“从(包括)范围[1,N]
中提取的m
数字的所有可能的有序序列”。使用“无置换”我的意思是,如果我已经找到115,我不想找到151或511。我不太确定返回什么{std::set()};dose,但这不能为我编译。@solid:它用一个空集初始化返回向量。你使用的是古老的编译器吗?@solid它可能在std::vector上中断,它应该在右尖括号之间有一个空格:std::vector@solid:您可以将其替换为std::vector(1)
(如果您的编译器太旧,请注意空格)。我正在使用VisualStudio2012,它在第一个返回行中抛出错误C2059:Syntaxfehler:“{”带空格和不带空格根据链接的输出不会给我122作为解决方案(我需要).但是如果我已经找到了122,我不想要122的排列,所以我不想要212或221。@solid啊,我明白了;而不是组合,你想要的是重复组合。链接库不包含此功能,但算法可以构建在的基础上,对于每个组合
@solid,我添加了一个实现基于每个组合()的重复组合的排序
template<typename Func>
void for_each_combination_with_repetition(int categories, int slots, Func func) {
std::vector<int> v(slots + categories - 1);
std::iota(begin(v), end(v), 1);
std::vector<int> indices;
for_each_combination(begin(v), begin(v) + slots, end(v), [&](auto b, auto e) {
indices.clear();
int last = 0;
int current_element = 0;
for(;b != e; ++last) {
if (*b == last+1) {
indices.push_back(current_element);
++b;
} else {
++current_element;
}
}
func(begin(indices), end(indices));
return false;
});
}
for_each_combination_with_repetition(N, M, [&](auto b, auto e) {
for(; b != e; ++b) {
int index = *b;
std::cout << index + 1 << " ";
}
std::cout << '\n';
});
template<typename Func>
void for_each_combination_with_repetition(int categories, int slots, Func func) {
std::vector<int> v(slots + categories - 1);
std::iota(begin(v), end(v), 1);
std::vector<int> repetitions(categories);
for_each_combination(begin(v), begin(v) + slots, end(v), [&](auto b, auto e) {
std::fill(begin(repetitions), end(repetitions), 0);
int last = 0;
int current_element = 0;
for(;b != e; ++last) {
if (*b == last+1) {
++repetitions[current_element];
++b;
} else {
++current_element;
}
}
func(begin(repetitions), end(repetitions));
return false;
});
}