题目描述:找n个数中r个数的组合。
1、算法设计 先分析数据的特点,以n=5,r=3为例
其中n为组合中的最大值,r为组合个数
在数组a中: a[1] a[2] a[3]
5 4 3
5 4 2
5 4 1
5 3 2
5 3 1
5 2 1
4 3 2
4 3 1
4 2 1
3 2 1
分析数据的特点,搜索时依次对数组(一维向量)元素a[1]、a[2]、a[3]进行尝试,
a[ri] i1——i2
ri为数组索引,也就是要找的组合数的位置。
a[1]尝试范围5——3
a[2]尝试范围4——2
a[3]尝试范围3——1
且有这样的规律:“后一个元素至少比前一个数小1”,ri+a[ri]均为4。
归纳为一般情况:
a[1]尝试范围n——r,a[2]尝试范围n-1——r-1,……,
a[r]尝试范围n-1+1——1.
由此,搜索过程中的约束条件为ri+a[ri]>=r+1,若ri+a[ri]<r就要回溯到元素a[ri-1]搜索,特别地a[r]=1时,回溯到元素a[r-1]搜索。
下面证明一下为什么是ri+a[ri]>=r+1
a[1]的最小值是r
a[2]的最小值是r-1
a[3]的最小值是r-2
a[4]的最小值是r-3
…
a[ri]的最小值是r-ri+1
…
a[r]的最小值是1
也就是说我们要设计的限制条件呢就是搜索到a[ri]的最小值之后就要回溯了。
即是a[ri]>=r-ri+1.
下面贴一下代码(在老师给的基础上改的)如有错误请指正!!!
#include<stdio.h>
void combination(int n,int r,int a[]);
int main()
{
int n,r;
int a[20];//数组的大小会限制n的值
n=4;
r=3;
a[0]=r;
combination(n,r,a);
}
void combination(int n,int r,int a[])
{
int i,ri;
ri=1;//数组下标索引
a[1]=n;//没有用数组的第一个元素
while(a[1]!=r-1)
{
if (ri!=r) //没有搜索到底
{
if (a[ri]>=r-ri+1)//向前搜索下一个数组元素
{
a[ri+1]=a[ri]-1;
ri=ri+1;
}
else //回溯上一个数组元素
{
ri=ri-1;
a[ri]=a[ri]-1;
}
}
else
{
for(int j=1;j<=r;j++)
{
printf("%d\t",a[j]);
}
printf("\n");
if (a[r]==1)//每次输出之后检查是否搜索完了
{
ri=ri-1;
a[ri]=a[ri]-1;
} //回溯
else//没有搜索完就减一
{
a[ri]=a[ri]-1; //搜索到下一个数
}
}
}
}