输出组合数,但是不使用递归
众所周知,在应用中递归容易导致各种各样的问题,这里给出了一种不使用递归输出组合数的方案。
这里的「组合数」就是 C m n C_m^n Cmn 对应的所有组合。例如 C 4 2 C_4^2 C42 对应了 6 6 6 种组合如下
0 1
0 2
0 3
1 2
1 3
2 3
人在书写组合数的时候是按照顺序书写的,同样地,利用这种顺序性,给定一个组合,程序可以计算下一个组合是什么,仍然以上面的例子来说,我们将组合看成从 0 0 0 到 3 3 3 中挑选数字的过程,上面的组合可以看作如下的挑选过程
0* 1* 2 3
0* 1 2* 3
0* 1 2 3*
0 1* 2* 3
0 1* 2 3*
0 1 2* 3*
注意到如果某一组合挑选了最后的连续若干个数,那么下一组合就是将这连续若干个挑选的数整体向前挪移的过程。
建议读者自己举几个例子更好理解。
以下给出程序
#include <iostream>
template<std::size_t N, std::size_t M>
void next(std::size_t array[N]) {
std::size_t nj = N;
while (array[nj - 1] == M - (N - nj) - 1) {
--nj;
}
++array[nj - 1];
for (std::size_t off = nj; off < N; ++off) {
array[off] = array[nj - 1] + (off - (nj - 1));
}
}
constexpr std::size_t comb_num(std::size_t N, std::size_t M) {
std::size_t ret = 1;
for (std::size_t i = 0; i < N; ++i) {
auto j = N - 1 - i;
ret *= (M - j);
ret /= (N - j);
}
return ret;
}
template<std::size_t N, std::size_t M>
void print() {
static_assert(M >= N);
std::size_t array[N];
for (std::size_t i = 0; i < N; ++i) {
array[i] = i;
}
for (std::size_t i = 0; i < comb_num(N, M); ++i) { // C(3, 6)
for (std::size_t j = 0; j < N; ++j) {
std::cout << array[j] << ' ';
}
std::cout << std::endl;
next<N, M>(array);
}
}
int main() {
print<4, 10>();
return 0;
}