这是我期中考试的问题之一。
请跟踪以下程序。修改该程序以编写一个递归程序int combinations(A, n, k)
,您可以打印出所有
存储在数组k
中的n
个不同数字中的A
个数字的组合,还有以下附加规则:
(1)必须保留A [0],A [1],...,A [n-1]的顺序,并且
(2)这些k
数字的顺序必须按升序排列。
例如,假设数组int A[4]
中存储了四个数字4,1,2,3。
调用此递归函数combinations(A, 4, 2)
将返回计数3并打印出(1、2),(1、3)和(2,3),或者调用combinations(A, 4, 3)
将返回计数1并打印出(1,2,3)。
您的递归程序必须考虑避免不必要的递归函数调用。
老师给出了以下代码作为提示
#include <stdio.h>
#define N 4
int boolfunc(int *var, int m);
int recursivebool(int *var, int n);
int main(){
int varbool[20];
recursivebool(varbool, N);
}
int boolfunc(int *var, int m){
int result=var[0], i;
for (i=1; i<m; i++) result = (result && var[i]);
return result;
}
int recursivebool(int *var, int n){
int localvar[20], i, j;
if (n == 0){
for(i=0; i<N; i++) printf("%d ", var[i]);
printf("%d\n", boolfunc(var, N));
return;
}
for (j=0; j<=1; j++) {
var[n-1] = j;
recursivebool(var, n - 1);
}
}
如果运行此程序,我们将获得如下输出:
0 0 0 0 0
1 0 0 0 0
0 1 0 0 0
1 1 0 0 0
0 0 1 0 0
1 0 1 0 0
0 1 1 0 0
1 1 1 0 0
0 0 0 1 0
1 0 0 1 0
0 1 0 1 0
1 1 0 1 0
0 0 1 1 0
1 0 1 1 0
0 1 1 1 0
1 1 1 1 1
我可以理解提示程序。我需要使用这个概念来编写int combination(int *A, int n, int k)
,就像所问的问题一样。据我所知,如果k
是2,我可以使用这个概念来找到具有两个1和两个0的场景,如下所示:
1 1 0 0
1 0 1 0
1 0 0 1
0 1 1 0
0 1 0 1
0 0 1 1
然后,我们可以从相应的索引1中找到数字,并检查数字以查看它们是否按升序排列。
我非常努力地解决了这个问题。但这太困难了。
答案 0 :(得分:1)
您可以将其作为一个简单的约束满足问题,并使用递归回溯法来解决约束。
正如您提到的,我们可以天真地生成所有可能的组合,然后追溯选择所需的组合,但是随后,我们做了很多无用的工作,这些工作被分配正确地禁止了。
一种解决方案是,一旦检测到违反约束条件就中断递归搜索,并尝试另一种可能性。如果我们达到了满足序列所有约束的地步,我们将打印结果。理想情况下,我们将返回一个结果数组,但不必这样做,这样就可以更轻松地专注于算法。
就满足约束而言,我们可以使用start
索引来满足i < j
的要求。如果我们向进行中的结果添加数字,则结果数组必须为空,或者数组末尾的现有元素小于我们要添加的元素。除此之外,我们还有k
的基本情况。
#include <stdio.h>
void print_arr(int len, int *a);
int combinations_recurse(int *a, int n, int k, int *selected,
int selected_len, int start) {
if (selected_len == k) {
print_arr(selected_len, selected);
return 1;
}
int selected_count = 0;
for (int i = start; i < n; i++) {
if (!selected_len || selected[selected_len-1] < a[i]) {
selected[selected_len] = a[i];
selected_count += combinations_recurse(a, n, k,
selected, selected_len + 1, start + 1);
}
}
return selected_count;
}
int combinations(int *a, int n, int k) {
int selected[n];
return combinations_recurse(a, n, k, selected, 0, 0);
}
int main() {
int a[] = {4, 1, 2, 3};
printf("count: %d\n\n", combinations(a, 4, 2));
printf("count: %d\n", combinations(a, 4, 3));
return 0;
}
void print_arr(int len, int *a) {
printf("[");
for (int i = 0; i < len - 1; printf("%d, ", a[i++]));
if (len) printf("%d]\n", a[len-1]);
else puts("]");
}
输出:
[1, 2]
[1, 3]
[2, 3]
count: 3
[1, 2, 3]
count: 1