在趣味无穷的数学世界里,如何使用计算机来解决数学问题,我们今天就来探究这个问题,我们以组合为例来感受计算机与数学之间的联系。计算机是离不开数学的,计算机的硬件设计离不开物理、电子、电路知识,而计算机软件又离不开数学知识,通过计算机与数学知识,可以解决很多生活中的问题。计算机中的算法于程序设计是将数学知识形式化的一门学科。
求m个元素的子集,就是从n个元素中找到m个元素,使之构成集合,该集合中有m个元素。这个问题与求所有子集的不同之处在于已经确定集合中的元素个数。
编写程序,把一个n个元素的集合{1,2,3,…,n}中的所有m个元素的子集用字典顺序列出来。例如, {1,2,3,4,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}
【分析】
按回溯法的思想,将找到的组合以从小到大的顺序存放到数组a[0],a[1],…,a[r-1]中,组合中的元素满足以下性质:
(1)a[i+1]>a[i],即后一个数大于前一个数;
(2)a[i]-i<=n-r+1。
按照回溯法思想,找解过程描述如下:
首先暂时不考虑组合数个数为r的条件,候选组合从只有一个数字1开始。因为该候选解满足除问题规模之外的全部条件,扩大其规模,并使其满足上述条件(1),得到候选组合1,2。继续这一过程,得到候选解1、2、3。该候选解满足包括问题规模在内的全部条件,因而是一个解。在该解的基础上,选下一个候选解,因 a[2]上的3调整为4和5都满足问题的全部要求,得到解1,2,4和1,2,5。由于对5不能继续进行调整,就要从a[2]回溯到a[1],可以将a[1]从2调整为3,并向前试探,得到解1,3,4。重复上述向前试探和向后回溯,直到从a[0]再回溯时,表明已经找完问题的全部解。
【程序】
#include<stdio.h>
#define MAX 100
int a[MAX];
void comb(int n,int r)
{
int i,j;
i=0;
a[i]=1;
do
{
if(a[i]-i<=n-r+1) /*还可以向前试探*/
{
if (i==r-1) /*找到一个组合*/
{
for(j=0;j<r;j++) /*输出一个组合*/
printf("%4d",a[j]);
printf("\n");
a[i]++;
continue;
}
i++; /*向前试探*/
a[i]=a[i-1]+1;
}
else /*回溯*/
{
if(i==0) /*找完全部解*/
return;
a[--i]++;
}
}while(1);
}
void main()
{
comb(5,3);
}
参考文献
[1]陈锐.《C/C++常用函数与算法速查手册》。中国铁道出版社,2011.11
[2]陈锐.《ilike就业visual basic多功能教材》。电子工业出版社,2011.12
[3]陈锐.《C语言从入门到精通》。电子工业出版社,2010.10