组合

在组合数学，一个集的元素的组合（）是一个子集。"S"的一个"k"-组合是"S"的一个有k个元素的子集。若两个子集的元素完全相同并顺序相异，它仍视为同一个组合，这是组合和排列不同之处。
表示方式.
从 n 个不同元素中取出 k 个元素的所有不同组合的个数，叫做从 n 个不同元素中取出 k 个元素的组合数，记做：formula_1、formula_2、formula_3、formula_4（英语）、formula_5（法语、罗马尼亚语、俄语、汉语、波兰语）。
理论与公式.
从formula_6个元素中取出formula_7个元素，formula_7个元素的组合数量为：
以六合彩为例。在六合彩中从49颗球中取出6颗球的组合数量为：
重复组合理论与公式.
从formula_6个元素中取出formula_7个元素，formula_7个元素可以重复出现，这组合数量为：
以取色球为例，每种颜色的球有无限多颗，从8种色球中取出5颗球，好比是在5颗球间画上分隔号“|”代表球色的分布情形(隔板法)。例如第1种色球取1颗，第2种色球取2颗，第3种色球取2颗可以表示成：
可以理解为8类球每类取多少个，一起构成5个球。我们把5个球排成一排，用7个分隔线去隔开。如上图，表示含义：第1根线前表示第一类球取的个数，第1根和第2根线表示第二类球取的个数...第6第7根线前表示第七类球的个数，第7根后表示第八类球的个数。亦即问题是从(5+8-1)个位置中挑选出(8-1)个位置摆分隔号，这组合数量为：
因为组合数量公式特性，重复组合转换成组合有另一种公式为：
另外formula_17也可以记为formula_18或formula_19
取值范围的扩充.
在formula_22的定义中，由于它有意义的范围必须是满足条件formula_23，所以其他范围必须另外定义，我们有:
演算范例.
组合 C.
回圈法.
/***********************/
/** This is C++ code. **/
/** Comb Example **/
using namespace std;
bool next_comb(vector&lt;int&gt;&amp; comb, const int n, const int k) {
 int i = k - 1;
 const int e = n - k;
 do
 comb[i]++;
 while (comb[i] &gt; e + i &amp;&amp; i--);
 if (comb[0] &gt; e)
 return false;
 while (++i &lt; k)
 comb[i] = comb[i - 1] + 1;
 return true;
int main() {
 int n, k;
 cout « "comb(n, k):" « endl;
 cin » n » k;
 if (n &lt; k || k &lt;= 0) {
 cout « "Invalid input: n must be &gt;= k and k must be &gt; 0." « endl;
 return 0;
 vector&lt;int&gt; comb(k);
 for (int i = 0; i &lt; k; i++)
 comb[i] = i;
 do {
 for (int i = 0; i &lt; k; i++) {
 cout « comb[i] + 1;
 if (i &lt; k - 1) cout « ',';
 cout « endl;
 } while (next_comb(comb, n, k));
 return 0;
递回法.
using namespace std;
namespace comb {
int n, k;
int arr[12];
int count;
bool arrsame(int site) {
 if (site &gt; 0 &amp;&amp; arr[site - 1] &gt;= arr[site])
 return 0;
 return 1;
inline void arrprint() {
 for (int i = 0; i &lt; k; i++)
 printf("%3d", arr[i]);
 puts("");
 count++;
void calculate(int now) {
 if (now == k) {
 arrprint();
 return;
 for (int i = 0; i &lt; n; i++) {
 arr[now] = i;
 if (arrsame(now)) {
 calculate(now + 1);
inline void run(int nn, int kk) {
 n = nn, k = kk;
 count = 0;
 if (k &lt; 12 &amp;&amp; n &gt;= k &amp;&amp; k &gt; 0)
 calculate(0);
 if (count)
 printf("\n%d combination.\n\n", count);
 else
 puts("Input error!");
int main() {
 int n, k;
 while (scanf("%d%d", &amp;n, &amp;k) != EOF) {
 comb::run(n, k);
 fflush(stdout);
 return 0;
重复组合 H.
回圈法.
/***********************/
/** This is C++ code. **/
/** ReComb Example **/
using namespace std;
bool next_re_comb(int* recomb, const int n, const int k) {
 int i = k - 1;
 do
 recomb[i]++;
 while (recomb[i] &gt; n - 1 &amp;&amp; i--);
 if (recomb[0] &gt; n - 1)
 return 0;
 while (++i &lt; k)
 recomb[i] = recomb[i - 1];
 return 1;
int main() {
 int n, k;
 cout « "recomb(n,k):" « endl;
 cin » n » k;
 if (n &lt;= 0 || k &lt;= 0)
 return 0;
 int* recomb = new int[k];
 for (int i = 0; i &lt; k; i++)
 recomb[i] = 0;
 do
 for (int i = 0; i &lt; k; cout « ((++i &lt; k) ? ',' : '\n'))
 cout « recomb[i] + 1;
 while (next_re_comb(recomb, n, k));
 delete[] recomb;
 return 0;
递回法.
using namespace std;
namespace re_comb {
int n, k;
int arr[12];
int count;
bool arrsame(int site) {
 if (site &gt; 0 &amp;&amp; arr[site - 1] &gt; arr[site])
 return 0;
 return 1;
inline void arrprint() {
 for (int i = 0; i &lt; k; i++)
 printf("%3d", arr[i]);
 puts("");
 count++;
void calculate(int now) {
 if (now == k) {
 arrprint();
 return;
 for (int i = 0; i &lt; n; i++) {
 arr[now] = i;
 if (arrsame(now)) {
 calculate(now + 1);
inline void run(int nn, int kk) {
 n = nn, k = kk;
 count = 0;
 if (k &lt; 12 &amp;&amp; k &gt; 0)
 calculate(0);
 if (count)
 printf("\n%d combination.\n\n", count);
 else
 puts("Input error!");
int main() {
 int n, k;
 while (scanf("%d%d", &amp;n, &amp;k) != EOF) {
 re_comb::run(n, k);
 fflush(stdout);
 return 0;
推广.
组合数可以推广到多分类的情形 ，我们将n个物品分为m份，每份的个数分别为:formula_25个，那么，总的分类数为