算法题:体彩29选7彩票组合(组合/回溯)
假设有一种29选7的彩票,每注由7个1~29的数字组成,且这7个数字不能相同,编写程序生成所有的号码组合。
代码如下:
#include <stdio.h>
#define MAXN 7 //设置每一注彩票的位数
#define NUM 29 //设置组成彩票的数字
int num[NUM];
int lottery[MAXN];
void combine(int n, int m)
{
int i,j;
for(i=n;i>=m;i--)
{
lottery[m-1]=num[i-1]; //保存一位数字
if (m>1)
combine(i-1,m-1);
else //若m=1,输出一注号码
{
for(j=MAXN-1;j>=0;j--)
printf("%3d",lottery[j]);
getchar();
printf("\n");
}
}
}
int main()
{
int i,j;
for(i=0;i<NUM;i++) //设置彩票各位数字
num[i]=i+1;
for(i=0;i<MAXN;i++)
lottery[i]=0;
combine(NUM,MAXN);
getchar();
return 0;
}
预处理和全局变量
cCopy#include <stdio.h>
#define MAXN 7 //设置每一注彩票的位数
#define NUM 29 //设置组成彩票的数字
int num[NUM]; // 存储从1到29的数字
int lottery[MAXN]; // 用于存放当前生成的彩票号码
在这里,#define
指令定义了每注彩票的数字位数(MAXN
为7位)和可用于组成彩票的数字范围(NUM
为29),即从1到29选择7个数字。数组num
用于存储这些数字,而lottery
数组则用于存储当前被选出来的一组彩票号码。
组合函数 combine
cCopyvoid combine(int n, int m) {
int i,j;
for(i=n;i>=m;i--) {
lottery[m-1]=num[i-1]; //保存一位数字
if (m>1)
combine(i-1,m-1);
else { //若m=1,输出一注号码
for(j=MAXN-1;j>=0;j--)
printf("%3d",lottery[j]);
getch();
printf("\n");
}
}
}
这是一个递归函数,其目的是生成所有可能的组合。它接收两个参数:n
代表还可以选择的数字数量,m
代表还需要选择的数字数量。算法的核心是递归地减少问题规模,直到达到基本情况(即需要选择的数字数量为0,m==1
)时输出一种组合。
lottery[m-1]=num[i-1];
这行将当前选定的数字加入到结果数组lottery
中。- 若
m>1
,则继续递归寻找剩余的数字组合;否则,打印当前找到的一组完整的组合。 - 注意,由于
combine
函数是以相反顺序填充lottery
数组的,因此在打印时也要反向遍历lottery
数组,以保证数字以正确的顺序显示。
主函数 main
cCopyint main() {
int i,j;
for(i=0;i<NUM;i++) //设置彩票各位数字
num[i]=i+1;
for(i=0;i<MAXN;i++)
lottery[i]=0;
combine(NUM,MAXN);
getch();
return 0;
}
主函数中,首先初始化num
数组为1到29的整数,然后将lottery
数组清零。之后调用combine
函数开始生成所有可能的组合。combine(NUM,MAXN);
这一行开始执行组合操作,即从29个数字中选择7个数字的所有组合。
注意事项
- 在原代码中使用
getch();
函数用于暂停屏幕输出。然而,请注意,getch()
是属于conio.h
库的一个函数,在某些编译器/环境中可能不可用或不标准。如果你遇到问题,可以尝试注释掉这些行或者使用其他方式实现类似的功能。 - 输出格式控制
printf("%3d",lottery[j]);
意味着每个数字占据至少3个字符宽度,以美化输出格式。
算法演示过程
假设我们从5个数字(1到5)中选择3个数字的所有可能组合,即NUM = 5
和MAXN = 3
来代替原始的29和7(为简单起见,这里不修改原代码,仅作为例子说明)。这样,我们需要找出所有可能的从数字集合{1, 2, 3, 4, 5}中选择3个数字的组合。
让我们逐步跟踪函数combine(5, 3)
的执行过程:
- 初始调用为
combine(5, 3)
,此时n=5
,m=3
。-
循环i从5开始递减至3:
-
当
i=5
时,lottery[2] = num[4] = 5
,接着调用combine(4, 2)
。combine(4, 2)
中,循环i从4开始递减至2:-
当
i=4
时,lottery[1] = num[3] = 4
,接着调用combine(3, 1)
。combine(3, 1)
中,循环i从3开始递减至1:- 当
i=3
时,lottery[0] = num[2] = 3
,没有更多递归调用,打印组合3 4 5
,对应的是从小到大选择数字。 - 当
i=2
时,lottery[0] = num[1] = 2
,同样没有更多递归调用,打印组合2 4 5
。 - 当
i=1
时,lottery[0] = num[0] = 1
,打印组合1 4 5
。
- 当
-
当
i=3
时,流程类似,最终会打印组合1 3 5
,2 3 5
。 -
当
i=2
时,流程类似,最终会打印组合1 2 5
。
-
-
当
i=4
和i=3
时,通过类似的递归调用,会顺序打印出剩余的组合。
-
-
通过上述示例,你可以看到combine
函数如何递归地构建每种可能的组合并打印它们。注意,这只是一个简化示例。在实际代码(使用29个数字中选择7个)中,组合的数量会大得多,但基本的执行过程相同:递归地选择每个数字,直到构建出完整的组合,然后打印该组合。